# Errors (/docs/api/errors)

The agent API and the MCP tools answer errors as `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)):

```json
{
	"type": "https://content.obelism.studio/docs/api/errors#insufficient_role",
	"title": "Your role in this organization does not allow this action.",
	"status": 403,
	"detail": "Your role (reader) does not allow this action.",
	"code": "insufficient_role",
	"hint": "Ask an admin of the organization for a role with more access."
}
```

A plain-text `403` with `error code: 1010` is Cloudflare's bot check, not the API: it blocks Python's default `Python-urllib/3.x` User-Agent at the edge. Set a custom User-Agent (or use `requests`/`httpx`) and the request reaches the API. A `404` for a Content endpoint called on `www.obelism.studio` means it lives on `content.obelism.studio`; www serves only accounts, organizations and spaces.

Act on `code`, never on `detail`'s wording. `invalid_content` adds `issues`, a list of `{ path, message }`. The [delivery](/docs/api/delivery#errors), [management](/docs/api/management) and [site](/docs/api/site) APIs answer the simpler `{ "error": "…" }`, with the same statuses: `413` for a file over 50 MB or a JSON body over its limit, `429` with `Retry-After` over a rate limit.

## Codes [#codes]

### invalid_json [#invalid_json]

The body isn't valid JSON. Send a JSON object with
`Content-Type: application/json`.

### invalid_request [#invalid_request]

A field or parameter is missing or invalid; `detail` names it.

### invalid_content [#invalid_content]

The content or definition doesn't fit the content model. `issues` lists every
problem as `{ path, message }`, with dotted paths into what you sent (e.g.
`body.0.heading.en`). Fix all of them, then send again.

### unauthorized [#unauthorized]

No bearer token, or it is invalid or expired. Sign in again.

### invalid_credentials [#invalid_credentials]

Email and password don't match an account.

### password_reset_required [#password_reset_required]

The account has to reset its password in the dashboard before signing in.

### invalid_verification_code [#invalid_verification_code]

The verification code is wrong or expired. Signing in sends a new one.

### unknown_organization [#unknown_organization]

The organization doesn't exist or you aren't a member. List yours with
`GET /api/agent/organizations`.

### unknown_space [#unknown_space]

The space isn't in that organization. List them with `GET …/spaces`.

### insufficient_role [#insufficient_role]

Your role doesn't allow this. Readers read; editors write and publish;
developers and admins change the model and manage API tokens, webhooks and
settings.

### product_disabled [#product_disabled]

An admin of the organization has disabled Content for it, in the
organization's settings on www.obelism.studio. The dashboard, MCP, this API
and the management API refuse it, whatever your role. Delivery and preview
keep serving your sites. Ask an admin to enable Content again.

### token_expired [#token_expired]

The API token expired: tokens are created to expire in 30 days, 90 days, a
year (the default) or never. Create a new one under Settings → API tokens, or
with createApiToken, put it where the old one was used, and revoke the old
one. The delivery and management APIs answer an expired token with `401` and
`"code": "token_expired"` too.

### token_not_allowed [#token_not_allowed]

A management token was sent where it may not be used. A token with the
`content` scope reaches the agent API's content routes (entries, assets, the
trash, redirects, and reading content types) of its own space and
environment only; everything else (tokens, webhooks, settings, the model,
promotion) needs a person's session. A token without the `content` scope
can't use the agent API at all. Create a management token with the scope you
need under Settings → API tokens, in the environment it should write.

### model_managed_by_code [#model_managed_by_code]

This environment's content model is managed in code: the dashboard, the
agent API and MCP can't change its content types. Change the model file in
the repository and apply it with `npx @obelism/content model apply` (the
management API), or have an admin or developer give the model back to the
dashboard under Settings → Publishing → Where the content model is changed.

### review_required [#review_required]

Publishing in this environment is reviewed: only admins publish, unpublish,
schedule, delete published entries, or promote and import published content
there. Ask for review with `POST …/entries/{entryId}/review` (or
`request_review` in `POST …/entries/bulk`); an admin approves it with
`…/review/approve`, which publishes it.

### production_protected [#production_protected]

The agent API doesn't make this change in production: creating or revoking
API tokens, creating or deleting webhooks, and changing the preview URL or
prompt endpoint. Ask a person with the admin or developer role to do it in the
dashboard under Settings, or make the change in `develop` or `staging`.

### resource_not_found [#resource_not_found]

The entry, content type, asset, API token or webhook doesn't exist in this
space and environment (a revoked token can't be revoked again).

### conflict [#conflict]

Someone changed it since you read it. Read it again and redo your change on
the current `draftRevision`.

### impact_required [#impact_required]

A shared block you are publishing is live on pages, and the request doesn't
say which of them it may update. Send `exclude`, a list of the pages to leave
on the version they show now; an empty list updates every live page.
`GET …/entries/<entryId>/publish-impact` lists them.

### rate_limited [#rate_limited]

Too many requests: the agent API and MCP take 300 a minute per person. Wait
the `Retry-After` seconds, then slow down.

### payload_too_large [#payload_too_large]

The body is too large. Files are limited to 50 MB; JSON bodies to 1 MB,
4 MB for entry content or a model file and 32 MB for an import file.

### not_found [#not_found]

No endpoint at this path. See `/openapi.json`.

### method_not_allowed [#method_not_allowed]

The endpoint exists but not for this HTTP method.

### internal_error [#internal_error]

Something went wrong on our side. Retry later.
