# Error codes

Source: https://docs.littlebigbrain.com/sdks/errors/

Every error from the data plane has a JSON body with one `error` object:

```json
{
  "error": {
    "type": "conflict_error",
    "code": "turn_lease_lost",
    "message": "the token no longer holds turn 3 of `ingest-7`: another attempt holds it, its lease ended, or it finished; stop this attempt",
    "param": "token",
    "request_id": "89ccd5ab-e545-4744-9909-769b393bb6d1",
    "doc_url": "https://docs.littlebigbrain.com/sdks/errors/#turn_lease_lost"
  }
}
```

| Field | Meaning |
| --- | --- |
| `type` | The class of the error, one of eight: `invalid_request_error`, `auth_error`, `permission_error`, `not_found_error`, `conflict_error`, `rate_limit_error`, `quota_error` and `api_error`. A code keeps the type it was first sent with, so many codes of status 404, 409 or 503 carry `invalid_request_error`. Each entry names its code's type. Branch on `code`, not on `type`. |
| `code` | The stable name of the error. Each code has one entry on this page. |
| `message` | A sentence for a person. Its words can change between releases. |
| `param` | The field, query parameter or header to change, when the error names one. Otherwise `null`. |
| `request_id` | The id of this request. The response's `X-Request-Id` header holds the same value. Quote it in a support message. |
| `doc_url` | The link to the code's entry on this page. |

Handle an error by its `code`. The SDKs raise this body as `LbbError`.

A retryable error also carries `retryable: true` and `retry_after_seconds`,
and the response has a `Retry-After` header. Wait that many seconds, then send
the same request again. An error that the same request meets again until
something else changes carries `retryable: false`.
[Back-pressure](https://docs.littlebigbrain.com/sdks/http-api/#back-pressure) and
[Read consistency](https://docs.littlebigbrain.com/sdks/http-api/#read-consistency) describe the busy and
waiting codes.

A 5xx answer to a write is an unknown outcome: the write may have landed.
Repeat it with the same `Idempotency-Key`. A write that landed returns its
first result as a replay.

A few codes appear in other places: in the `error` of a job on
`GET /v1/graph/activity`, or in a status field. Their entries say where.

## Requests and parameters

### `branch_not_supported`

400 · `invalid_request_error`

The request names a branch other than `main`. A graph has one history, so
`main` is the only branch value it takes. Remove `branch` or `branch_id`, or
set it to `main`.

### `conflict`

409 · `conflict_error`

A write precondition failed, or the resource already exists. On a
`/v1/workflows/turns/*` route, the token still holds the turn, but it sends
another checkpoint at a position the turn recorded. A lost lease answers
[`turn_lease_lost`](#turn_lease_lost) instead. Read the current state before
you write again.

### `graph_epoch_fence_unsupported`

400 · `invalid_request_error`

The request sends `expected_graph_epoch` to a route that takes no graph epoch
precondition. `param` is `expected_graph_epoch`. Send the request without it.

### `idempotency_conflict`

409 · `conflict_error`; the review routes send it as `invalid_request_error`

The `Idempotency-Key` is bound to an earlier request with other content.
Import jobs, `PUT /v1/files/pages` and the review routes answer it. `param` is
`Idempotency-Key`. Use a new key for a new request.

### `internal_error`

500 or another 5xx · `api_error`

The server failed in a way the request did not cause. The body names no
detail. The server log keeps it under the request id. Retry later, and quote
`request_id` if it repeats. A stream of server-sent events can end with an
`error` event of this code.

### `invalid_api_version`

400 · `invalid_request_error`

The `Lbb-Version` header is no date `YYYY-MM-DD`, such as `latest` or
`2026-7-23`. `param` is `Lbb-Version`. Send `2026-10-21`, or `2026-07-23`
for the earlier list shapes, or leave the header out.

### `invalid_idempotency_key`

400 · `invalid_request_error`

The `Idempotency-Key` header is empty or malformed. A key has 1 to 255
characters: letters, digits, `-`, `_`, `.`, `:` and `/`. `param` is
`Idempotency-Key`.

### `invalid_request`

400 · `invalid_request_error`

The request is malformed: an unknown field, a missing field, or a value out of
range. The `message` names the problem, and `param` names the field when the
server can tell. The same request fails the same way, so fix it before you
send it again.

### `missing_idempotency_key`

400 · `invalid_request_error`

The route needs an `Idempotency-Key` header, and the request has none.
`POST /v1/graph/commit`, `POST /v1/graph/import-jobs` and
`POST /v1/ontology/drafts/promote` need one. `param` is `Idempotency-Key`.

### `not_found`

404 · `not_found_error`

No such graph, record, job or route. For a path that matches no route,
`did_you_mean` lists close routes. Check the path and the ids in the request.

### `route_moved`

404 · `not_found_error`

The route has a new path. The `message` names it, and `did_you_mean` holds
it. Send the request to the new path.

### `spool_too_large`

413 · `invalid_request_error`

The declared `Content-Length` of an upload is larger than the server's budget
for request bodies on disk. The server answers before it reads the body. Split
the data into smaller uploads.

## Authentication and access

### `forbidden`

403 · `auth_error`

The credential is valid, but it may not use this route or this resource. Use
a credential with the access the route needs.

### `scoped_access_denied`

403 · `auth_error`, or `invalid_request_error` where a route checks it

A scoped credential does not cover the request. `POST /v1/query/dataset`
answers it when the credential does not authorize every graph of the
selection. The application token routes answer it to a caller that is not an
environment administrator. Use a credential that covers every graph the
request reads.

### `stack_endpoint_mismatch`

403 · `auth_error`

Hosted stacks: the host of the request names one stack, and the key or session
belongs to another. Copy the endpoint and the key from the same stack's
**Connect** view.

### `stack_endpoint_required`

421 · `routing_error`

Hosted stacks: the host of the request is missing or malformed, or it is not
a complete stack endpoint. Send the request to the complete stack endpoint,
`https://<tenant-short-id>--<stack-slug>.db.eu.littlebigbrain.com`.

### `unauthorized`

401 · `auth_error`

The key is missing, wrong or revoked. Send `Authorization: Bearer <key>` with a
live key of the stack.

## Graphs, writes and history

### `edge_property_not_projectable`

400 · `invalid_request_error`

An owned write on an RDF-native graph carries an edge property value that has
no RDF form. Nothing was written. Change or remove that value.

### `graph_epoch_changed`

409 · `invalid_request_error`

The graph was deleted, or deleted and created again, after the request's epoch
was read. `param` names the epoch the request sent, such as
`expected_graph_epoch`. An import job answers it with `param` `graph` when the
graph was deleted: create the graph before you start a new import. Otherwise
read the graph's current epoch before you send the request again.

A `POST /v1/workflows/activities/ground` request sends no epoch. It reads the
epoch at its start and at its end. The graph may be deleted and created again
in between. Then the request answers this code with no `param`, and it gives
no verdict. Send the request again. Use the files and `uploaded_at` stamps of
the new graph.

### `graph_not_found`

404 · `not_found_error`

The stack has no graph with this name. `param` is `graph`, and `known_graphs`
lists the graphs of the stack. Pass an existing `graph=`, or create the graph
with `POST /v1/graph/create` or a first commit.

### `graph_reclaim_in_progress`

429 · `rate_limit_error`

A graph of this name was deleted, and the server still removes its data. A
create of the same name waits until that pass ends. Retry after `Retry-After`
(30 seconds).

### `graph_recreated`

400 · `invalid_request_error`

The graph was deleted or created again while an owned write ran. Nothing was
written. Read the graph again before you repeat the write.

### `historical_generation_unavailable`

400 · `invalid_request_error`

The commit in `as_of_commit_seq` is no longer retained. `param` is
`as_of_commit_seq`. The server never answers from a nearby commit, so a retry
does not help. A read with `as_of_valid_time` gets this code too. Read a
retained commit, or the latest data. See
[Time travel](https://docs.littlebigbrain.com/sdks/http-api/#time-travel).

### `ingest_busy`

429 · `api_error`

The graph's writes are catching up. Causes include a full queue of
unpublished writes, many writers on the graph at once, a large rebuild, or an
eventual read of a graph with nothing published yet. Retry the same request
after `Retry-After`. A write with the same `Idempotency-Key` is safe to
repeat.

### `missing_job_id`

400 · `invalid_request_error`

A `GET` or `DELETE` of `/v1/graph/import-jobs` has no `job_id`. `param` is
`job_id`. Pass the id that the start of the job returned.

### `owned_rdf_needs_rdf_native`

400 · `invalid_request_error`

An owned RDF write was sent to a records graph. A records graph writes owned
outputs with `replace_owned` on `POST /v1/graph/commit`.

### `rdf_native_graph`

400 · `invalid_request_error`

The graph is RDF-native, and the request uses a records route: a JSON triplet
commit, an NDJSON import or a retract. A starter workflow that does not support
this graph's kind answers it too. Write the graph with
`POST /v1/graph/import/rdf` or SPARQL Update. See
[RDF-native graphs](https://docs.littlebigbrain.com/sdks/http-api/#rdf-native-graphs).

### `reserved_namespace`

400 · `invalid_request_error`

The write names reserved vocabulary: an `lbb:` or `ep:` predicate, or a
statement node as a subject. The server writes these terms itself. Remove
those statements from the write.

## Queries and reads

### `carried_floor_entity_projection_unsupported`

400 · `invalid_request_error`

The read asks for entity metadata, such as a `fields` projection, a metadata
filter or facets, while the published generation serves an earlier commit than
the one its entity columns hold. `param` names that parameter. Drop it and
send the read again.

### `commit_not_found`

400 · `invalid_request_error`

`POST /v1/query/compare` cannot place a `date` or a `moment` on a commit. The
point is before the first commit, or the commits have no time. `param` is
`before` or `after`. Pass the commit itself with `as_of_commit_seq`, or a
later point.

### `family_not_enabled`

400 · `invalid_request_error`

The read needs an index family that the graph's published generation does not
hold. `param` is `family`, and the message names it: `base`, `rdf`, `bm25` or
`ann`. Read the graph with SPARQL.

### `invalid_commit_at_request`

400 · `invalid_request_error`

`GET /v1/graph/commit-at` needs exactly one of `date=YYYY-MM-DD` and
`moment=<RFC 3339>`. `param` names the parameter that is missing, doubled or
malformed.

### `invalid_compare_request`

400 · `invalid_request_error`

A field of `POST /v1/query/compare` is outside its limits. Examples are a
query that does not parse or is not a `SELECT`, a `key` the query does not
project, a point after the later one, or a cursor of another request. `param`
names the field.

### `invalid_describe_request`

400 · `invalid_request_error`

A field of `POST /v1/query/describe` is outside its limits: a question over
4,000 characters, more than 20 classes, or more than 50 properties. `param` is
`question`, `classes` or `properties`.

### `invalid_names_request`

400 · `invalid_request_error`

A field of `POST /v1/query/names` is outside its limits: an empty or too long
`text`, or a `limit` out of range. `param` is `text` or `limit`.

### `pagination_cursor_expired`

410 · `invalid_request_error`

The server can no longer serve the commit that a SPARQL page cursor pins.
`param` is `cursor`. Restart the listing with `cursor: ""`.

### `peer_read_incomplete`

503 · `api_error`

The server forwarded the read to the graph's home server, and that server did
not complete the answer. The read did not run a second time on the first
server. Retry after `Retry-After` (1 second).

### `published_format_migration_pending`

429 · `api_error`

The server rebuilds the graph's published data in a new format after an
upgrade. Reads wait until the rebuild ends. Writes keep working. Retry after
`Retry-After`.

### `query_deadline_exceeded`

503 · `api_error`

The read ran past its deadline: 25 seconds for a public read, 60 seconds
for a question (`POST /v1/query/ask`). Retry after
`Retry-After`. If it repeats, narrow the query: bind a subject or a class, or
add a `LIMIT` the engine can apply early.

### `read_your_writes_pending`

429 · `api_error`

The published data does not cover the floor in `min_indexed_seq` yet
(`min_commit_seq` on `/v1/query/names`). A floor above the newest commit gets
this code until a commit reaches it. Retry the same request after
`Retry-After`.

### `result_too_large`

400 · `invalid_request_error`

The result is larger than one response may hold, or one join step inside the
query built too many rows. `param` is `query`. The same query fails the same
way. Narrow it, page it with a cursor, or join patterns on a shared variable.

### `scan_too_wide`

400 · `invalid_request_error`

The query's plan needs more reads than one request may make. `param` is
`query`. The same query fails the same way. Bind a subject or a class, or
split the query.

### `strong_read_pending`

429 · `api_error`

A strong read on the summary, conformance or structured-query route waits for
publication to cover the newest commit. Retry the same request after
`Retry-After`.

## Search and questions

### `embedding_budget_exceeded`

429 · `rate_limit_error`

The stack's monthly embedding budget is spent. The body has
`retryable: false`. Search by meaning works again after the budget resets. An
embedding job that stops for this reason shows the code in its `error` on
`GET /v1/graph/activity`.

### `embedding_not_ready`

409 · `invalid_request_error`

The search names an embedding whose first version still builds. `param` is
`embedding`, and the message gives the instances done so far. Retry after
`Retry-After` (5 seconds), or wait until `GET /v1/embeddings?name=` shows
`serving`.

### `embeddings_unavailable`

503 · `api_error`

The server has no embedding model, so it refuses an embedding declaration. The
body has `retryable: false`. The operator sets up a model:
`LBB_OPENROUTER_API_KEY`, or `LBB_EMBED_PROVIDER=mock` on a local server. An
embedding job shows this code in its `error` too.

### `invalid_ask_request`

400 · `invalid_request_error`

A field of `POST /v1/query/ask` is outside its limits, or belongs to the
removed one-shot mode (`run`, `previous`, `mode: "rewrite"`). `param` names
the field, and the message says what to use instead.

### `invalid_rewrite_profile`

400 · `invalid_request_error`

A write of the query profile (`/v1/query/rewrite/profile`) is outside its
limits, or an example query does not parse or is not a `SELECT` or an `ASK`.
`param` is `notes` or `examples`.

### `invalid_search_settings`

400 · `invalid_request_error`

A value of `PUT /v1/search/settings` is out of bounds. `param` names the
field. Send a value inside the bounds, or `null` to set the field back to its
default.

### `invalid_tuning_request`

400 · `invalid_request_error`

A field of `POST /v1/search/tuning` is out of range: `queries` is 6 to 40, and
`rounds` is 1 to 3. `param` names the field.

### `parameter_missing`

400 · `invalid_request_error`

A search by meaning has no `text`. `param` is `text`.

### `rewrite_limit`

429 · `rate_limit_error`

The environment used its questions of the UTC day on this server for
`POST /v1/query/ask`, 500 by default. Ask again on the next UTC day. The tools
for agents (`/v1/query/names`, `/v1/query/describe`, `/v1/query/compare`) call
no model and do not count.

### `rewrite_model_unavailable`

503 · `api_error`

The model of `POST /v1/query/ask` did not answer, or the server has none.
`mode: "route"` needs no such model. Retry later.

### `tuning_no_proposal`

409 · `conflict_error`

`POST /v1/search/tuning/apply` names a session that has no proposal to
apply: it is still running, it failed, or it found no better settings.
Apply a done session with a proposal.

### `tuning_running`

409 · `conflict_error`

A tuning session of the graph is open already. Wait until it ends, or stop
it, then start a new one.

### `tuning_unavailable`

409 · `conflict_error`

The graph cannot be tuned now: the server has no embedding model, or the
graph has no embedding that serves. The message says which. Add an
embedding to the graph and let it serve, then start again.

## Ontology and schema

### `document_not_parsed`

409 · `invalid_request_error`

`POST /v1/ontology/fit-text` names a file without parsed pages. Run the Parse
documents workflow on the file first.

### `fit_budget_exceeded`

429 · `rate_limit_error`

The stack's monthly budget for fit sources and fit from text is spent. The body
has `retryable: false`. Fitting works again after the budget resets.

### `fit_models_unavailable`

503 · `api_error`

The server has no reasoning or decision model for fit sources and fit from
text. The body has `retryable: false`. The operator sets up the models. A
starter workflow that needs them shows `unavailable` with this reason.

### `fit_text_invalid`

400 · `invalid_request_error`

`POST /v1/ontology/fit-text` needs exactly one non-empty `text` or `document`.
`pages` goes only with a document, with 1 <= `from` <= `to`.

### `ontology_identity_breaking_change`

400 · `invalid_request_error`

`POST /v1/ontology/define` would drop an entity type or a relation that the
graph still defines. Nothing was written. `param` is `source`, and the message
lists the dropped subjects. Keep them in the document, or change the ontology
with `POST /v1/ontology/evolve`.

### `ontology_restrictive_change`

400 · `invalid_request_error`

`POST /v1/ontology/define` would narrow the declared domain or range of a
relation. Nothing was written. `param` is `source`. The message lists the
relations and names the route that confirms the change.

### `ontology_unsupported_change`

400 · `invalid_request_error`

A difference in `POST /v1/ontology/define` has no additive operation. Examples
are a retyped property field, a changed set of allowed values, or a vector
field. `param` is `source`. Make the change with `POST /v1/ontology/evolve`,
which names each change as its own operation.

### `shacl_write_validation_budget`

400 · `invalid_request_error`

A write to an RDF-native graph under a `reject` shape set needs more
validation than one write may spend: more than 250,000 focus nodes, or more
than 2,000,000 reverse lookups. Nothing was written. Split the write into
smaller writes.

### `shapes_not_write_enforceable`

400 · `invalid_request_error`

The shape set uses `sh:sparql` or a recursive shape reference. The server
cannot check such a set on an RDF-native graph before a write lands.
`POST /v1/schema/publish` refuses `reject` mode for the set there, and a write
under such a set is refused. The message names the shape and the reason.
Publish the set in `warn` mode, or remove those shapes.

### `starter_conflict`

409 · `conflict_error`

`POST /v1/ontology/starters/apply` found a term that the graph holds
differently: a property with another value type, a relation with another
cardinality or inverse, or a class with other parents. Nothing was applied.
`param` is `starter`, and `details.conflicts` lists the terms.

### `starter_not_applied`

409 · `conflict_error`

`POST /v1/ontology/starters/update` names a starter that the graph holds no
part of. `param` is `starter`. Apply the starter instead.

### `starter_not_found`

404 · `not_found_error`

The catalog of ontology starters has no starter with this id. `param` is
`starter`. `GET /v1/ontology/starters` lists them.

### `suggestion_superseded`

409 · `invalid_request_error`

The accept names an ontology change suggestion that a newer suggestion
replaced. The message carries the producer's reason. For a review item, it
names the item that took its place. Read the newer suggestion and accept that
one.

## Workflows and turns

### `activity_effect_conflict`

409 · `conflict_error`

A `/v1/workflows/activities/*` request reuses an `effect_id` whose kept answer
belongs to another request. `param` is `effect_id`. Use a new `effect_id` for
a new request.

### `activity_model_unavailable`

503 · `api_error`

An activity found no model, or the model did not answer. Without a model the
body has `retryable: false`. When the model did not answer, retry after
`Retry-After` (5 seconds).

### `activity_request_refused`

422 · `invalid_request_error`

The model provider refused the request of an activity (HTTP 400, 413 or 422),
or the model gave no usable answer. The body has `retryable: false`. Split the
request into smaller ones, or change it.

### `derivation_invalid`

400 · `invalid_request_error`

A derivation key on `/v1/workflows/derivations/*` has a part outside its
characters or its length.

### `derivation_upload_changed`

409 · `invalid_request_error`

`POST /v1/workflows/derivations/record` names an upload in
`content_uploaded_at` that is no longer the live upload of its file. The file
was deleted, deleted and uploaded again, or reclaimed since the check. Nothing
was recorded. The run of the current upload does the work.

### `ground_timeout`

503 · `api_error`

A `POST /v1/workflows/activities/ground` request reached its deadline of 10
seconds. The answer holds no verdict. Retry after `Retry-After` (2 seconds),
with fewer items or smaller files. A request that finishes gives each item a
verdict in `results`, and a failed item has a `code` in the body of the
result, not an error.

### `named_workflow_not_found`

404 · `invalid_request_error`

The graph has no workflow with this name, or the workflow has no trigger with
this id. `param` is `name` or `trigger`. `GET /v1/workflows/named` lists the
workflows.

### `reserved_workflow_id`

403 · `invalid_request_error`

Only Little Big Brain's own worker creates an instance with this id, such as
`model-checks` or `calibration`. `param` is `id`. Choose another instance id.

### `reserved_workflow_type`

403 · `invalid_request_error`

The request creates an instance of a reserved `lbb.*` workflow type, claims
one of its turns, or writes for it. Only Little Big Brain's own worker does
that. `param` is `workflow_type`. Reads, messages and controls of these
instances stay open to you.

### `starter_request_refused`

Internal · not sent as an HTTP answer

The model provider refused a call of a workflow that Little Big Brain runs, as
invalid or too large (HTTP 400, 413 or 422). The workflow splits the request
into smaller ones. The activity routes answer this case with
`activity_request_refused`.

### `template_runs_in_worker`

400 · `invalid_request_error`

A create or a preview through `/v1/workflows/triggered` names a template that
runs in your own worker, such as `rows` or `sections`. `param` is `starter`.
Create its workflow with `PUT /v1/workflows/named`. The message names the
project command.

### `triggered_workflow_not_found`

404 · `invalid_request_error`

The graph has no workflow of this starter workflow with this name. `param` is
`name`. A workflow with a content trigger is not on the
`/v1/workflows/triggered` routes. Read it with `/v1/workflows/named`.

### `try_needs_saas_mode`

400 · `invalid_request_error`

Try on samples creates a new graph in the stack. A server in single mode
serves one graph, so it refuses the try.

### `try_unsupported`

400 · `invalid_request_error`

Try on samples has no samples for this starter workflow: `workflow`,
`documents.map`, `review`, `rows` or `sections`. `param` is `starter`.

### `turn_lease_lost`

409 · `conflict_error`

A `/v1/workflows/turns/*` request sends a `token` that no longer holds the
turn. Another attempt holds it, its lease ended, the turn waits after a sleep
or signal checkpoint, or it finished. A different retry of that checkpoint,
or another result for a finished turn, answers this code too. `param` is
`token`, and `retryable` is `false`. Stop this attempt and send nothing more
for the turn. A worker of an older SDK stops on any `409` as well.

### `workflow_budget_exceeded`

429 · `invalid_request_error`

The stack's model budget for workflows is spent, or the workflow's own
`budget_usd_per_month`. The body has `retryable: false`. On the activity
routes, `retry_at` gives the start of the next month. Raise the budget in the
console
(**Environments → Model budget**), or wait for the reset.

### `workflow_cycle`

409 · `invalid_request_error`

The create or change would make workflows wake each other in a cycle: each one
owns an output that the next one watches. `param` is `owns`, and
`details.cycle` lists the workflows. Change what one of them watches or owns.

### `workflow_fence_lost`

409 · `invalid_request_error`

A commit's `workflow_fence` no longer holds its turn: the lease ended, or
another worker holds it. Nothing was written. The body has `retryable: false`.
Stop the turn. A repeat of a commit that landed answers with its replay.

### `workflow_not_found`

404 · `invalid_request_error`

The server's catalog has no starter workflow with this id, or none at this
version. `param` is `starter`. `GET /v1/workflows/starters` lists them.

### `workflow_outputs_remove_unsupported`

400 · `invalid_request_error`

A workflow delete sends `outputs=remove`. `param` is `outputs`. Delete with
`outputs=keep`, then retract the workflow's owned facts with a commit that
carries `replace_owned`.

### `workflow_owns_conflict`

409 · `invalid_request_error`

Two workflows would own the same output: a class, a relation or a property.
`param` is `owns`, and `details` names the outputs and their owners. Give each
output one owner.

### `workflow_param_invalid`

400 · `invalid_request_error`

A parameter of a workflow request is invalid. The request can create or
change a workflow, or read its runs, run results or documents. Examples are a
`params` key the starter workflow does not take, a name that a workflow of
another starter holds, a trigger of the wrong kind, or an `lbb.*` type on
`PUT /v1/workflows/named`. On a read, examples are a `run` that is no run id,
an unknown `outcome`, or a `cursor` that is not the `next_cursor` of a page.
`param` names the parameter, and the message says why.

### `workflow_pause_unsupported`

400 · `invalid_request_error`

The pause names a starter workflow without triggers, such as `search.embed`
or `ontology.fit`. `param` is `starter`.

### `workflow_revision_conflict`

409 · `invalid_request_error`

An activation names an `expected_revision` that the workflow no longer has
bound: another change or activation came first. `param` is
`expected_revision`. List the revisions again, check the bound one, then
activate again if you still want to.

### `workflow_revision_not_found`

404 · `invalid_request_error`

The workflow keeps no revision with this id. The history keeps the newest
100 activations, and a revision that none of them names is deleted. A run
summary keeps the id of its revision after that. `param` is `id`, or
`revision` on a test create (`POST /v1/workflows/named/tests`).

### `workflow_revision_stale`

409 · `invalid_request_error`

An activation sends the revision's settings through the change path, and the
graph now resolves them to other settings, for example after a field was
renamed. Nothing was written. `param` is `id`. Change the workflow with a
`PUT` that names the settings you want.

### `workflow_run_not_found`

404 · `invalid_request_error`

The workflow has no run with this id. A run of an earlier workflow with the
same name is not its run. `param` is `run`.

### `workflow_scheduling_not_live`

400 · `invalid_request_error`

The scheduling source of a model workflow (model checks, search tuning,
trials or calibration) no longer exists. Its environment was deleted, or its
graph epoch was replaced. A retry does not help.

### `workflow_shards_busy`

409 · `invalid_request_error`

A change of `shards` or `route_by` met a shard inbox that holds messages, or
the watch changed after the server checked the inboxes. `param` is `shards`.
Pause the workflow, let the inboxes drain, then change it.

### `workflow_source_closure_pending`

503 · `api_error`

The delete of a workflow instance still cleans up its source records. Retry
the same delete after `Retry-After` (1 second). The retry continues the
cleanup.

### `workflow_stream_full`

429 · `rate_limit_error`

A send of events (`POST /v1/workflows/named/events`) would pass the
stream's backlog: 10,000 events or 64 MiB received and not yet sent. The
request wrote nothing. Retry after `Retry-After` (5 seconds). The backlog
drains as your worker handles the batches; a paused workflow sends none.
The stream is also full while LBB has not read its events for 15 minutes.

### `workflow_stream_rate_limited`

429 · `rate_limit_error`

A send of events passed the workflow's rate on the node: 100 events per
second, bursts of 500. The request wrote nothing. Retry after
`Retry-After` (1 second) with the same events: each event's `id` is its
idempotency key.

### `workflow_trigger_unsupported`

400 · `invalid_request_error`

The workflow names more than one watch, content trigger, schedule or
stream, or a trigger kind that this release does not run. `param` is
`triggers`. A workflow takes exactly one of them, and at most one review
trigger.

### `workflow_watch_required`

400 · `invalid_request_error`

A create or a preview has no `watch`, or an empty `watch.class`. A named
workflow's trigger needs a `watch` that names a class, or a `content` trigger
that names media types. `param` is `watch` or `triggers`.

### `workflows_disabled`

503 · `invalid_request_error`

The request needs the workflow engine, and this server does not run it
(`--workflows`). A starter workflow that needs the engine shows `unavailable`
with this reason. The operator starts the server with workflows on.

## Workers and execution credentials

### `batch_capacity_deferred`

Internal · not sent as an HTTP answer

A batch phase of a workflow found no database capacity before it started. The
workflow engine defers the turn: it waits with reason `capacity` and counts no
attempt.

### `batch_database_busy`

429 · `api_error`

A turn's read through its execution credential found no batch database
capacity, so it did not run. Retry the same read after `Retry-After` (1
second), or let the workflow's retry policy recover the turn.

### `invalid_workflow_execution_credential`

401 · `invalid_request_error`

The execution credential is invalid or already expired. Ask for a new one with
`POST /v1/workflows/turns/execution-credential` through the worker's control
bearer.

### `owner_reserved`

403 · `invalid_request_error`

A commit sends `owner=`, and the caller is not one of Little Big Brain's
hosted workers with an `owned_write` grant. `param` is `owner`. Send the
commit without `owner=`. The versioned records adapter also refuses reserved
internal owners in the body. Use an ordinary authorized application/source
scope; body fields cannot impersonate a managed workflow or source adapter.
A trusted owned-RDF write on a graph with a support root also refuses the owners
`application` and `cdc:…`. They belong to the shared `application/default`
scope and to a source's row scopes.

### `write_outside_owns`

403 · `permission_error`

A commit under a workflow turn writes a property that its workflow does not
own. Nothing was written. `details.kind` is `property`, and `details.iris`
lists up to 10 IRIs outside `owns.properties`. Or `details.kind` is
`property_merge`, and `details.iris` is empty. Then the commit sets
`property_merge: "replace"`. Replace erases fields the workflow may not own.
Merge instead. The server may first write such a commit and only count it.
Add the property to the workflow's `owns`, or stop writing it. A
`ValueSource` entity may carry `property`, `value` and `support`. The same
names on another class are checked. The workers of the TypeScript and Python
SDKs stop retrying this refusal with their next release.

### `work_lease_lost`

409 · `invalid_request_error`

The worker no longer holds the work board entry: its lease ended, or it was
released. `param` is `work_id`. Stop work on that graph, and claim again with
`POST /api/workers/work/claim`.

### `worker_credential_scope`

403 · `invalid_request_error`

A worker credential is used outside the routes it allows. A pool credential
reaches the board routes (`/api/workers/*`) only. A work token creates and
claims Little Big Brain's own workflow types only.

### `worker_secret_missing`

400 · `invalid_request_error`

The server has no worker secret (`LBB_WORKER_SECRET`). Pool credentials and
workflow execution credentials need one, shared by every node. The operator
sets it.

### `workflow_execution_disabled`

403 · `invalid_request_error`

Workflow execution credentials are off on this server, or the hosted workers'
grants (`file_read`, `owned_write`) are off. The operator turns on
`LBB_WORKFLOW_EXECUTION_ENABLED` and batch admission, and
`LBB_WORKFLOW_EXECUTION_GRANTS` for the grants.

### `workflow_execution_lease_lost`

403 · `auth_error`, or `invalid_request_error` where a route checks it

The workflow lease behind an execution credential is missing, expired or
replaced, or the credential expired after authentication. The server refuses
further requests with this credential. Stop the turn.

### `workflow_execution_scope`

403 · `auth_error`, or `invalid_request_error` where a route checks it

An execution credential is used for another operation than the one it names,
or a caller other than the hosted workers asks for `file_read` or
`owned_write`. Ask for a credential of the operation the route needs.

## Review

### `invalid_cursor`

400 · `invalid_request_error`

`GET /v1/reviews` got a `cursor` that it did not give out. `param` is
`cursor`. Send the `next_cursor` of the page before, or no cursor for the
first page.

### `review_answer_kind`

400 · `invalid_request_error`

The `decision` of the answer does not fit the item's kind. Read the item, then
answer with a decision its kind takes.

### `review_answer_option`

400 · `invalid_request_error`

The chosen `option` is not one of the item's options.

### `review_answer_value`

400 · `invalid_request_error`

The corrected `value` does not fit the property under the current ontology:
an undeclared property, a value of another type, or a unit of another kind.
Nothing was recorded.

### `review_answered`

409 · `invalid_request_error`

The item has an answer already, and this answer differs from it. The same
answer again returns the item.

### `review_kind_clash`

409 · `invalid_request_error`

`POST /v1/reviews` names a key that holds an item of another kind: a plain
suggestion filed under it before. File the item under another key.

### `review_origin_reserved`

403 · `invalid_request_error`

`POST /v1/reviews` or `POST /v1/ontology/suggestions` names an origin that only
the server files under (`evals:checks`, `evals:calibration`, `evals:golden`,
`evals:datasets`).
An answer to such an item writes a label of Evals. File the item under an
origin of your own.

### `review_stale`

409 · `invalid_request_error`

The item was revised after the `revision` that the answer names. Read the item
again, then answer.

## Evals, models and checks

### `calibration_apply_needs_person`

403 · `invalid_request_error`

In SaaS mode a person applies a measured gate from a console session. An apply
sent with an API key gets this code. Set a gate by hand with
`PUT /v1/workflows/triggered` instead.

### `calibration_no_proposal`

409 · `invalid_request_error`

An apply of a calibration when the labels support no lower gate. The message
says why.

### `calibration_not_asking`

409 · `invalid_request_error`

An answer to a calibration session that takes no answers: it has no
questions yet, it failed, or a newer session of its job replaced it. In the
Review inbox the question's item is withdrawn. Start a new session.

### `checker_unavailable`

503 · `api_error`

The server has no checker model, so it cannot check a call or score a
tuning session. Configure a checker model for the data plane, or ask your
operator.

### `eval_dataset_items_too_large`

400 · `invalid_request_error`

An answer in the Review inbox gives a label to a dataset's item. The label
would make the dataset's items larger than 8 MiB. Delete items you no longer
need, or move some to a second dataset. Then answer again.

### `experiment_arms_mixed`

400 · `invalid_request_error`

An experiment's B names a model and a revision. One experiment compares
one change, so its difference has one cause and its B applies in one
write. Start one experiment per change. `param` is `b`.

### `experiment_outdated`

409 · `conflict_error`

A write with `experiment` (a model choice, or a revision activation) whose
workflow no longer runs the experiment's A: the workflow was made again,
its settings revision moved, or the model of a use changed since the
experiment started. The message names the part. B was compared with a
configuration that is no longer in use, so run the experiment again. A
repeat of an apply that succeeded does not get this code: it finds B in
use and changes nothing. `param` is `experiment`.

### `experiments_instance_taken`

409 · `conflict_error`

The graph has a workflow instance with the id `eval-experiments` of
another type, made before Little Big Brain reserved the id for its
experiments. Experiments cannot run on the graph until it is gone. Delete
that instance, then start the experiment again.

### `invalid_calibration_request`

400 · `invalid_request_error`

A field of a `/v1/models/calibration` request is invalid. Examples are a job
that is not a choice job, a missing or extra `workflow`, a workflow of another
starter, or an option out of range. `param` names the field.

### `invalid_check_review`

400 · `invalid_request_error`

The body of `POST /v1/models/checks/review` breaks a rule. Examples are an
agreement that sends a verdict, a correction without the right verdict, or a
`score` outside 0 to 1. `param` names the field.

### `invalid_trial_request`

400 · `invalid_request_error`

A field of `POST /v1/models/trials` is invalid. `param` names it.

### `model_call_not_checkable`

400 · `invalid_request_error`

`POST /v1/models/calls/check` names an `embed` call or a failed call. Neither
has an answer to check. `param` is `id`.

### `model_choice_unavailable`

409 · `conflict_error`

`PUT /v1/models/choices` names a model this server cannot run now: it holds
no key for the model's provider, or it has no price for the model, so the
calls could not count against a budget. Pick another model of the row's
`options` (each says `available`), or ask your operator to add the key.
`param` is `model`.

### `model_choice_unsupported`

400 · `invalid_request_error`

A model choice the use cannot take. `param` is `use` for a use with no
choice (`embed`: vectors of two models do not compare) or an unknown use.
`param` is `model` for a model outside the use's `options`, or an effort
the model does not take. Read the row's `options` with
`GET /v1/models/choices?use=…`.

### `switch_unsupported`

409 · `conflict_error`

`POST /v1/models/switches` names a trial whose task cannot run on the
candidate's provider. Pick a candidate of a provider that runs the task.

### `training_budget_exceeded`

429 · `rate_limit_error`

`POST /v1/models/train` refuses a run while the tenant is over its monthly GPU
training budget. The body gives the used amount and the limit. Train again
after the monthly reset or a raised limit.

### `trial_candidate_unavailable`

409 · `conflict_error`

The server has no key for the trial's candidate provider, so the switch
cannot use it. Add the provider's key to the data plane, or test another
candidate.

### `trial_not_qualified`

409 · `conflict_error`

The trial does not meet the bar for a switch: too few calls compared, or
the candidate did worse. Read the trial's `report`. Let the trial run
longer, or keep the current model.

### `trial_outdated`

409 · `conflict_error`

The task uses another model now than the one the trial compared with.
Start a new trial against the current model, then switch.

### `trials_unavailable`

503 · `api_error`

The server cannot run model trials: it runs without the workflow engine, or
its catalog names no checker model. The message says which. Ask your
operator to turn on workflows or to add a checker model.

## Files and documents

### `file_generated`

409 · `invalid_request_error`

Reserved. No route writes a generated file yet.

An upload by a person or a stack key holds the bytes of a generated file. A
generated file is one that a workflow run wrote. Its bytes are not a source.
Nothing was stored. Delete the generated file, then upload the bytes again.

### `file_not_found`

404 · `invalid_request_error`

The graph has no file with this `sha256`. `param` is `sha256`.
`GET /v1/files` lists the files.

### `file_not_parsed`

404 · `invalid_request_error`

`GET /v1/files/pages` names a file whose pages are not parsed yet. Run the
Parse documents workflow on it, or store pages with `PUT /v1/files/pages`.

### `file_not_spreadsheet`

400 · `invalid_request_error`

`GET /v1/files/sheets` names a file that is no XLSX workbook. A workbook has
the media type
`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`, or a
ZIP or untyped file named `.xlsx`.

### `file_output_content`

400 · `invalid_request_error`

Reserved. No route writes a generated file yet.

The bytes of a generated file are not UTF-8 text, hold a NUL byte, or are not
one JSON value when the type is `application/json`. Nothing was stored.

### `file_output_limit`

403 · `invalid_request_error`

Reserved. No route writes a generated file yet.

One message writes at most 5 generated files and 4 MiB in all. This file
would pass one of these caps. Nothing was stored. A file written before still
answers.

### `file_output_type`

415 · `invalid_request_error`

Reserved. No route writes a generated file yet.

A generated file is `text/plain` (`.txt`), `text/markdown` (`.md` or
`.markdown`) or `application/json` (`.json`). The type or the extension of the
name is another, or they do not match. The name holds no control or format
character. Nothing was stored.

### `file_pages_conflict`

409 · `invalid_request_error`

`PUT /v1/files/pages` sends other pages under a parser id that already holds
pages for this file. A parser id names one output. `param` is `parser`. Send
the new pages under another parser id.

### `file_pages_invalid`

400 · `invalid_request_error`

The pages of `PUT /v1/files/pages` fail the shape check, or the `parser` id is
not 1 to 64 letters, digits, `.`, `_` or `-`. `param` is `pages` or `parser`.

### `file_reclaim_in_progress`

429 · `rate_limit_error`

An upload, a pin or a delete of a file whose bytes a reclaim pass holds. A
pass ends in seconds. Retry after `Retry-After` (5 seconds).

### `file_too_large`

413 · `invalid_request_error`

The upload to `POST /v1/files` is larger than the files limit
(`LBB_FILES_MAX_BYTES`, 1 GiB by default). The server answers before it reads
the body.

### `file_transfers_busy`

503 · `api_error`

The server sends as many file bodies at once as it allows, 16 by default. The
read waited 2 seconds for a slot. Retry after `Retry-After` (1 second).

### `file_upload_changed`

409 · `invalid_request_error`

`PUT /v1/files/pages` names an upload in `uploaded_at` that is no longer the
file's live upload. The file was deleted and uploaded again since. Nothing was
stored.

### `source_generated`

400 · `invalid_request_error`

Reserved. No route sends this code yet.

A generated file is a file that a workflow run wrote. It has an `origin`. It
is never evidence for a fact. When the check lands, `ground` gives the item the
verdict `source_generated`. The commit seam and the Review answer path refuse
that evidence. They answer `400 evidence_not_verified` with `details.reason`
set to `source_generated`. Cite a file that a person or a source system
uploaded.

### `parser_unavailable`

503 · `invalid_request_error`

The `documents.parse` workflow needs the `pdftotext` and `pdfimages`
programs (Poppler). The server cannot run one of them. The body has `retryable: false`. The operator
installs Poppler, or sets `LBB_PDFTOTEXT` and `LBB_PDFIMAGES` to the paths of
the programs.

`GET /v1/files/sheets` answers it too, for a workbook the server has not read
yet. In that case the server cannot run Python 3. The operator installs Python
3.9 or later, or sets `LBB_PYTHON3` to the interpreter's path. A workbook the
server has read is served without it.

### `sheet_not_found`

404 · `invalid_request_error`

`GET /v1/files/sheets` names a `sheet` the workbook does not have. Read the
outline (no `sheet`) for the names.

### `xlsx_busy`

503 · `api_error`

A node parses two workbooks at once, and a tenant one. The read waited 2
seconds for a slot. Retry after `Retry-After` (5 seconds).

### `xlsx_refused`

400 · `invalid_request_error`

The reader refused the XLSX workbook. The message names the reason. A reason
is one of three kinds:

- A limit: `xlsx_limit` (sheets, rows, columns, cells or elements),
  `xlsx_cell_too_long`, `xlsx_file_too_large`, `xlsx_members`,
  `xlsx_expanded_too_large` or `xlsx_output_too_large`.
- A file the reader does not read: `xlsx_invalid`, `xlsx_encrypted`,
  `xlsx_macros`, `xlsx_dtd`, `xlsx_encoding` or `xlsx_unreadable`.
- A stop that depends on the server: `xlsx_time_limit`, `xlsx_memory`,
  `xlsx_io` or `xlsx_crashed`.

The refusal covers the whole workbook. The server stores a limit, or a file
the reader does not read. The same file is refused again. The server does not
store a stop. It remembers the stop for 15 minutes, and another server tries
once.
The limits are in [Spreadsheets](https://docs.littlebigbrain.com/guides/documents-to-graph/#spreadsheets).

### `range_not_satisfiable`

416 · `invalid_request_error`

`GET /v1/files/content` got a `Range` with no byte of the file: a first byte
at or past the end, or `bytes=-0`. The response has
`Content-Range: bytes */<length>`.

## Background jobs

These codes appear in the `error` of a job on
[`GET /v1/graph/activity`](https://docs.littlebigbrain.com/sdks/http-api/#graph-activity). They are not HTTP
answers. For more detail, give the job's `id` to support.

### `admission_unrunnable`

Job error · `GET /v1/graph/activity`

The server's maintenance capacity cannot ever admit this publication job. The
message gives the admission diagnostic that
`GET /v1/graph/publication-status` reports. `retryable` is `false`, because
the job estimate and the capacity are fixed when the server starts.

### `data_missing`

Job error · `GET /v1/graph/activity`

Stored data that the job needs is missing.

### `job_failed`

Job error · `GET /v1/graph/activity`

An internal error stopped the job. Give the job's `id` to support.

### `storage_data_error`

Job error · `GET /v1/graph/activity`

Stored data did not pass an integrity check: a decode or a checksum failed.

### `storage_unavailable`

Job error · `GET /v1/graph/activity`

A request to object storage failed: a timeout, a transport fault, or a 5xx or
throttling answer. While `retryable` is `true`, the job tries again.

### `write_conflict`

Job error · `GET /v1/graph/activity`

Another update changed the graph first. While `retryable` is `true`, the job
tries again.

## Applications, catalog and reference datasets

These routes are optional, and each needs its deployment feature.

### `application_access_disabled`

403 · `permission_error`

Application tokens are not enabled on this server. `POST /v1/access/tokens`
needs the deployment feature.

### `application_catalog_disabled`

403 · `permission_error`

The application catalog routes (`/v1/catalog/*`) are not enabled on this
server.

### `application_usage_handoff_unconfirmed`

503 · `api_error`

The write ran, but the server could not confirm its usage reporting
measurement. The body has `retryable: false`, and the response has no
`Retry-After`. Check the state of the operation before you send it again: a
new request can run and be measured again.

### `application_usage_rate_limited`

429 · `api_error`

Usage report pages (`GET /v1/catalog/usage`) are rate limited per environment:
a burst of 8, then 2 a second. Retry after `Retry-After` (1 second).

### `application_usage_unavailable`

503 · `api_error`

Usage reporting admission is unavailable, so the request did not run. Retry
after `Retry-After` (2 seconds).

### `application_usage_work_budget`

400 · `invalid_request_error`

One pass of usage reporting work spent its bound of object reads, writes and
bytes. Recovery waits and runs the work again.

### `application_views_disabled`

400 · `invalid_request_error`

Saved dataset views (`/v1/catalog/views`, `/v1/catalog/view`) are not enabled
on this server.

### `catalog_operation_unsupported`

400 · `invalid_request_error`

The catalog has no such operation. In this release, ownership, names and
bindings cannot be moved, deleted or reused.

### `reference_datasets_disabled`

403 · `permission_error`

Reference dataset queries (`POST /v1/query/dataset`) are not enabled on this
server.

### `reference_datasets_require_environment`

403 · `permission_error`

Reference datasets need a managed environment. A server in single mode
refuses them.

### `reference_generation_changed`

409 · `invalid_request_error`

A newer publication of a reference graph won while the read pinned the commit
in `as_of_commit_seq`. `param` is `as_of_commit_seq`. Read the source's
current published commit, then send the query again.

## Change data capture (CDC)

The `/v1/cdc/*` routes are off by default (`LBB_CDC_ENABLED`). See
[HTTP API](https://docs.littlebigbrain.com/sdks/http-api/) for their scope.

### `apply_paused`

409 · `invalid_request_error`

The apply mode of the graph's CDC binding is not running. A control credential
sets the mode with `POST /v1/cdc/apply/mode`.

### `capture_backpressure`

429 · `invalid_request_error`

The CDC capture reached its capacity, and the append did not land. Retry it
later.

### `capture_paused`

409 · `invalid_request_error`

The CDC capture is paused. The apply worker can still read captured batches. A
control credential resumes capture with `POST /v1/cdc/capture/mode`, and a
reader then claims a new lease.

### `capture_retired`

400 · `invalid_request_error`

The CDC capture of this graph epoch has ended, and the end is permanent for
the epoch. It takes no new credentials. Create the graph again for a new
epoch, and set up CDC on it.

### `cdc_already_configured`

400 · `invalid_request_error`

`POST /v1/cdc/discovery` names a graph that already has a CDC binding.

### `cdc_apply_budget`

400 · `invalid_request_error`

One CDC apply exceeds its bound of object work: too many bytes or statements
in one batch, or a counter at its limit.

### `cdc_conflicting_mapping`

400 · `invalid_request_error`

The CDC mapping maps two columns of a table to one predicate, or maps a column
to `rdf:type`. Give each column its own predicate.

### `cdc_corrupt_data`

400 · `invalid_request_error`

Stored CDC data failed its decode or its checksum.

### `cdc_credential_invalid`

403 · `invalid_request_error`

The CDC worker credential is invalid, expired or revoked, outside its role, or
for another graph. Issue a new credential with `POST /v1/cdc/credentials`.

### `cdc_discovery_expired`

400 · `invalid_request_error`

The discovery setup expired before the source was registered. Start a new
discovery.

### `cdc_fork_unsupported`

400 · `invalid_request_error`

`POST /v1/graph/fork` names a CDC-bound graph. A copy cannot take over the
source's ownership and apply authority.

### `cdc_invalid_input`

400 · `invalid_request_error`

A CDC request body or query parameter does not parse, or misses a field. The
message gives no detail, so that it never repeats a source row or a token.
Check the request against the API contract.

### `cdc_invalid_iri`

400 · `invalid_request_error`

A CDC mapping or row produces a string that is not a valid IRI.

### `cdc_invalid_rdf`

400 · `invalid_request_error`

The server could not write the statements of a CDC row as N-Triples.

### `cdc_invalid_source_value`

400 · `invalid_request_error`

A source value does not fit its type. Examples are a number without digits, a
float that is not finite, or hex binary of odd length or with other
characters.

### `cdc_main_branch_required`

400 · `invalid_request_error`

A CDC request names a branch other than `main`.

### `cdc_not_configured`

400 · `invalid_request_error`

The graph has no CDC binding. Activate CDC on it first.

### `cdc_owned_predicate`

400 · `invalid_request_error`

A write to a CDC-bound graph sets a predicate that the CDC mapping owns on a
CDC row. Change that value in the source database.

### `cdc_ownership_conflict`

400 · `invalid_request_error`

The statements of a CDC row name a subject other than the row's own IRI.

### `cdc_storage_error`

Router status · `failure` of the CDC customer router

An object storage request failed while the router routed a source unit. The
next routing pass clears the failure and routes the unit again.

### `cdc_target_not_empty`

400 · `invalid_request_error`

CDC activation needs a fresh graph, and the target graph already holds data.
Activate CDC on a new graph. The `activation` health of a setup can show this
code too.

### `cdc_truth_writes_disabled`

503 · `service_unavailable`

CDC writes are off on this server until its reviewed release gate is on. The
status routes stay readable.

### `cdc_unsupported_format`

400 · `invalid_request_error`

Stored CDC data has a format that this server does not read.

### `content_conflict`

409 · `invalid_request_error`

The scope, operation identity or content of a CDC request conflicts with
durable state. Examples are another graph epoch, another scope, or other
content at a captured sequence. Read the status again before you retry.

### `customer_ownership_unresolved`

400 · `invalid_request_error`

The CDC customer router cannot resolve which customer graph a source row
belongs to. A parent row is missing, a key column is absent, or a link points
to another customer's row. The source unit stays in capture.

### `customer_transfer_required`

400 · `invalid_request_error`

A source change moves a row to another customer, such as a parent move or a
key move across customers. This release does not route ownership transfers.

### `schema_action_required`

409 · `invalid_request_error`

The source schema matches no schema that the approved mapping names. Review
and approve a new mapping for it.

### `sequence_gap`

409 · `invalid_request_error`

The CDC sequence or source checkpoint is not contiguous. The request's
expected sequence differs from the applied one, or a checkpoint is ahead of
captured data. Read the status and continue from the next sequence.

### `source_repair_required`

409 · `invalid_request_error`

The source image needs a consistent repair. Examples are a snapshot that did
not finish, or applied progress below the retained capture. Start a new
snapshot attempt.

### `stale_batch`

409 · `invalid_request_error`

The batch is outside the retained verification coverage, so the server does
not apply it again. Ask for the next unapplied unit with
`POST /v1/cdc/apply/next`.

### `stale_reader`

409 · `invalid_request_error`

The CDC reader is fenced, or its lease expired. Claim a new lease with
`POST /v1/cdc/capture/claim`.

### `stale_worker`

409 · `invalid_request_error`

The CDC apply worker is fenced, or its lease expired. Claim a new lease with
`POST /v1/cdc/apply/claim`.

## Billing, plans and limits

### `account_access_paused`

403 · `account_error`

The stack's account has neither an active Free plan nor an active paid plan.
Choose a plan for the account in the console.

### `batch_billing_quota_exceeded`

402 · `invalid_request_error`

The account's billing quota refuses a batch phase of a workflow. The model
runner that runs in the server parks the turn for 60 seconds before it checks
again.

### `billing_unavailable`

503 · `api_error`

The server could not read the account's billing state. Retry after
`Retry-After` (5 seconds).

### `billing_usage_preparing`

202 · no `type`

`GET /api/control/billing/usage` has no usage totals yet, and the server
prepares them. The body has `ok: false` and `retry_after_seconds: 5`. Ask
again after 5 seconds. The SaaS API passes it to the console as a 503 with
this code, and the console's billing page checks again every 5 seconds.

### `billing_usage_unavailable`

503 · `api_error`

`GET /api/control/billing/usage` could not read the usage totals in time.
Retry after `Retry-After` (5 seconds).

### `free_fair_share_busy`

429 · `api_error`

The server is busy, and this Free account uses more than its fair share: 4
requests at once, more only while the server is under half load. The request
used no request slot. Retry after `Retry-After` (1 second).

### `free_managed_models_unavailable`

403 · `quota_error`

Managed models need Cloud. Search by meaning (embeddings) is available on
Free.

### `free_plan_unavailable`

503 · `api_error`

The server could not read the Free account's allowance. Retry after
`Retry-After` (2 seconds).

### `free_query_admission_unavailable`

503 · `api_error`

The server could not read the Free account's request allowance. Retry after
`Retry-After` (2 seconds).

### `free_query_rate_limited`

429 · `api_error`

Free allows 300 requests per rolling minute, reads and writes together. Retry
after `Retry-After`.

### `free_storage_limit_reached`

403 · `quota_error`

The account reached its Free storage allowance. Writes that grow storage are
refused. Reads, export and deletion still work. Delete data, or upgrade to
Cloud.

### `quota_exceeded`

402 · `quota_error`

The account cannot run more work until a person acts on its plan: the
`message` says what to do, for example add a card to activate Cloud. Do it in
the console's Billing page, then send the request again.

### `spending_limit_reached`

402 · `billing_error`

The account's spending limit pauses new paid work. Raise or turn off the limit
in Billing, or wait for renewal.

## Capacity and storage

### `cache_tier_managed`

409 · `api_error`

The cache is shared and managed automatically. `POST /v1/stack/cache-tier`
refuses any increase. `param` is `gb`. A request with `gb=0` is accepted.

### `index_busy`

429 · `rate_limit_error`

An index build for this graph is running, the server is at its build limit,
or a ranged index is not ready. Retry after `Retry-After`.

### `rate_limit_exceeded`

429 · `rate_limit_error`

A rate limit of the data plane applies: per client address, per stack, or on
the authentication routes. Retry after `Retry-After`, and lower the request
rate.

### `server_busy`

429 · `api_error`

This server is briefly busy. It is short of memory, of room for request
bodies, or of request slots, or the server that owns this graph's writes is
too busy. A refused request did not run. Retry after `Retry-After`. A job
shows this code in its `error` on `GET /v1/graph/activity` when the server was
busy with other work.

### `storage_degraded`

503 · `api_error`

Object storage is unreachable, or a request to it failed. Retry after
`Retry-After` (5 seconds).

## Operator routes

These codes come from routes for the people who run the servers.

### `application_usage_capture_repair_disabled`

400 · `invalid_request_error`

`POST /api/admin/application-usage/capture/abort` is off, because
`LBB_APPLICATION_USAGE_CAPTURE_REPAIR` is `off` or unset. Capture repair needs
that setting at `apply`.

### `historical_target_retired`

Campaign receipt · `/api/admin/workflows/historical-discovery`

The target graph of a historical discovery campaign no longer has the
incarnation that the campaign observed. The campaign counts the target as
gone and continues.

### `node_holds_overrides`

409 · `conflict_error`

`DELETE /api/ops/placement/node` names a node that a placement override
targets. Add `&force=true` to drop those overrides with the node. Their units
then return to the default placement.

### `provider_operation_busy`

503 · `invalid_request_error`

Another Slack token operation on `POST /api/admin/provider-apps/claim` is in
progress, or the provider app policy changed during the request. Retry after
`Retry-After` (2 seconds).

### `provider_protocol_required`

503 · `invalid_request_error`

A Slack token operation on `POST /api/admin/provider-apps/claim` lacks an
explicit `operation` or the ownership proof that this route needs. The trusted
host must send the current request form with verified app ownership.

### `source_or_storage_error`

Campaign receipt · `/api/admin/workflows/historical-discovery`

A historical discovery campaign could not seed a target: a source or storage
request failed, or the seed was refused. The receipt counts it as an
unresolved error.

### `version_mismatch`

412 · `conflict_error` or `precondition_failed`

A versioned write names an `expected_version` that differs from the stored
one. `POST /api/admin/stack-settings` answers with `conflict_error` and
`param` `expected_version`. `POST /v1/cdc/metadata` answers with
`precondition_failed`. Read the current document, then write again.

## Graph metadata diagnostics

### `graph_metadata_budget`

Graph metadata refused an RDF root or F3-header diagnostic read above its
16 MiB control-object budget. This is not an invalid RDF format and ordinary
RDF reads can remain valid. Use the publication-status endpoint for workflow
progress where appropriate. The metadata default still follows RDF authority;
legacy index lineage requires explicit `include_indexes=true`.

## Exact RDF record reads

These codes apply to the [records/1 entity read](https://docs.littlebigbrain.com/guides/records/) and explicitly activated record bindings. They carry `invalid_request_error`; the schema revision conflict uses HTTP 409, the others HTTP 400.

### `record_parameter_ambiguous`

Conflicting repeated parameters or graph-scope aliases would make the selected record or revision ambiguous. Supply one value; identical repetitions are accepted.

### `record_parameter_unknown`

The records/1 query contains an unknown parameter. Correct misspelled guards or limits; they are never silently ignored.

### `record_version_required`

Send `version=records/1` when addressing a full `iri` on the entity resource. The SDK retrieve method sets it.

### `record_version_unsupported`

Use `records/1`, or omit the version for the existing native entity view.

### `record_selector_invalid`

Supply exactly one full `iri`, native `id`, or schema-bound `type` plus `key`. Do not mix selectors or send legacy `name`, `edges` or `evidence` options.

### `record_identity_invalid`

Supply a valid absolute IRI or a nonempty key. Custom keys preserve their exact UTF-8 bytes; native identities keep their established mapping.

### `record_read_limit`

The complete read cannot fit a positive section, point-probe, term or MCP-output bound. Increase an adjustable bound within its ceiling, use HTTP for a result exceeding the MCP budget, or query selected facts with SPARQL. No partial record was returned.

### `record_read_predicate_budget`

The graph has no complete bounded predicate directory for this read, or exceeds its 1,024-predicate ceiling. Use a bounded SPARQL query; the reader will not scan the whole graph as a fallback.

### `record_schema_snapshot_unavailable`

The selected historical or lagged snapshot cannot prove its activated schema. Read by full IRI/native id without a schema guard, or use a current strong read for a schema-bound key. Retrying an unchanged historical request does not repair missing schema history.

### `schema_revision_conflict`

The current exact schema differs from the requested opaque `schema_revision`. Inspect the new configuration and deliberately refresh the guard; do not silently retry with a different identity mapping.

### `schema_binding_invalid`

The explicitly activated binding annotations have invalid terms, syntax or an unsupported combination. Correct the schema source before publishing it.

### `schema_binding_ambiguous`

Two explicit aliases of the same kind resolve the same normalized spelling to different IRIs. Rename or remove the conflicting binding; declaration order does not choose a winner.

### `schema_binding_missing`

The activated schema has no binding for this alias. Use its full IRI or explicitly publish a binding.

### `schema_key_binding_missing`

A custom class needs an explicit activated `keyPrefix` before a stable key can resolve. A display name is never used as a fallback.

## RDF mutation preparation

These are internal U2 preparation codes. The new mutation write route and
durable support activation are not enabled by these types. Preparation returns
`invalid_request_error` without a partial normalized result; it publishes no
facts, support or source progress. Public adapters must preserve the code when
they expose the operation.

### `mutation_budget`

The intent exceeds a byte, statement-work, selector or quoted-term depth bound.
Raw duplicates count toward work. Reduce the whole transaction; do not split a
scope replacement or source transaction into partial successful writes.

### `mutation_cleanup_budget`

Scoped entity cleanup exceeds its selector, selected-support, incident-statement
or expanded projected-removal limit. The entire mutation is refused before
immutable uploads. Narrow the authorized target; do not turn one intended
transaction into silently partial cleanup. Independent source support is retained.

### `mutation_cancelled`

Mutation preparation observed cancellation before acceptance. Immutable shadow
objects may already exist, but they do not publish a partial transaction. After
an ambiguous earlier response, retry with the original key and payload to
establish whether a durable receipt already exists.

### `mutation_term_invalid`

An explicit RDF IRI, blank label or literal envelope is invalid. Correct the
term; numeric values are not repaired or coerced during normalization.

### `mutation_term_storage_unsupported`

The current RDF storage codec cannot reconstruct the exact term. Directional
language literals, including inside quoted terms, currently meet this refusal.
Changing only the request key cannot fix it. A qualified storage-format change
is required before that form can be admitted without losing information.

### `mutation_identity_invalid`

A logical writer, owner, scope or stable blank-node scope is empty or contains
only whitespace. Supply its explicit authorized identity. Meaningful bytes
are preserved; trimming is not an identity mapping.
The same code answers a request that names a scope whose owner is not the
request's logical writer. A writer may state, withdraw, replace or clean up only
its own scopes. Send the request under the owner of the scope.

### `mutation_blank_scope_required`

Explicit blank labels need a stable request or durable import scope before
hashing. Query-local labels alone do not establish cross-request identity.
Use the original stable scope for retry, or supply a durable full IRI.

### `mutation_conflict`

One support has incompatible operations, or the intent contains contradictory
commit/triple guards. Correct the whole intent; input order does not choose a
winner.

### `assertion_identity_conflict`

An assertion id is already bound to a different kind or exact described tuple.
Withdrawal and request-receipt expiry do not free that identity. Use a distinct
assertion id for a distinct claim; changing metadata does not change its tuple.

### `mutation_assertion_invalid`

Bare-triple support must have its deterministic internal id, `asserted=true`
and no structured-claim metadata. Use a structured claim with its own full IRI
when independent evidence or an unasserted claim is intended.

### `mutation_assertion_reserved`

A caller claim uses the internal bare-assertion namespace. Supply its own
authoritative IRI. Existing data with an internal-namespace collision needs
migration preflight; it is never silently renamed.

### `mutation_assertion_metadata_invalid`

Structured metadata targets another subject or contradicts the claim's reserved
reification tuple. Attach metadata to its assertion id and keep the described
subject, predicate and object immutable.

### `schema_revision_required`

A mutation key or alias needs an exact activated schema revision. Bind against
the configuration selected by the core; a display name or ad hoc request schema
cannot replace that pin.

### `schema_snapshot_unavailable`

The mutation cannot prove the exact configuration requested by its revision
guard. A retained replay uses the original receipt's captured configuration;
it must not silently rebind against a newer mapping.

## Atomic RDF support state

These codes describe the internal U2 coordinator and shadow store. There is no
public activation route in this slice. A graph must pass the format, retention
and adapter qualification gates before it can use this write model.

### `rdf_mutation_not_enabled`

The selected graph has no activated atomic RDF support root. This refusal does
not convert the graph or recommend a destructive reset.

### `rdf_mutation_writer_required`

A legacy writer cannot update this support-enabled graph because it would omit
atomic ownership, history or receipts. Use the qualified shared mutation adapter;
retrying the old route cannot restore compatibility.

### `rdf_mutation_source_unsupported`

The write path cannot take this request. The whole request is refused and
nothing is written. The message names the cause.

A source-bound graph requires its atomic source-progress adapter. The generic
mutation path cannot advance or bypass CDC ownership, fencing or progress.

A write path that is not open to every graph yet uses the same code for a
request member or an operation form that it has no place to store. Remove the
member, or send the request through the path the message names.

### `rdf_mutation_condition_failed`

The expected commit or an RDF presence/absence condition was false at the
attempt's exact head. No new acceptance was published. Read current state and
submit a deliberately revised operation with a new key when appropriate.

### `rdf_mutation_idempotency_conflict`

The logical writer's retained key names a different semantic payload. Preserve
the original payload for replay; a different intended transaction needs a new
key. Changing current schema or conditions does not invalidate an old receipt.

### `rdf_mutation_receipt_exists`

An internal storage caller tried to prepare another receipt for a key already
present in its snapshot. The coordinator must resolve that receipt before new
preparation; this is not permission to replace accepted history.

### `rdf_mutation_state_invalid`

The proposed internal support state, captured configuration, identity or receipt
violates its versioned contract. Correct the producing adapter. Do not rewrite
an authoritative root or silently treat invalid state as empty.

### `rdf_mutation_state_budget`

Support preparation, configuration reads or closure verification exceeded a
count, byte or cursor bound. The complete operation is refused. A continuation
that exhausts its whole-closure bound is not a completeness receipt, and a
large source transaction must not be silently split into partial acceptances.

### `rdf_mutation_state_cancelled`

Support-store work observed cancellation. Previously uploaded immutable shadow
objects remain invisible unless an authoritative head already references them.
Retry an ambiguous operation with its original key to recover its exact receipt.

### `rdf_mutation_state_format_unsupported`

The internal support state names a format version that this build does not
read. The version may be older or newer. The root is refused before any of its
child objects is read. The state is not damaged, and it is not empty. There is
no conversion. Use a build that reads that format.

## Internal migration metadata preflight

These codes belong to the read-only U7 inventory helper. There is no public
preflight route, activation or migration-readiness guarantee. A successful
metadata inventory still reports unresolved catalog, retained-schema, parity
and migration-machinery gaps. Shared immutable/support readers may also return
their existing budget, cancellation, corruption and storage errors.

### `rdf_migration_preflight_invalid`

An explicit legacy owner/scope selector is invalid, or its supplied reference
does not match the exact graph, epoch and existing scope-key builder. The
request is refused before fetching any caller-selected key.

### `rdf_migration_preflight_unsupported`

The selected head, CDC state or legacy ownership ledger uses an unsupported
format, or the head is a tombstone requiring a separate retired-incarnation
inventory. This refusal does not authorize conversion or a format reset.

### `rdf_migration_preflight_head_changed`

The graph identity/epoch differs from the requested pin, or the head/selected
mutable register changes or disappears during inventory. No consistent
inventory report is returned. A final head check certifies only captured head
references; it cannot certify an independently mutable ownership catalog.

### `rdf_migration_preflight_budget`

The complete metadata inventory exceeds its object, byte, output, scope or
history bound. No partial result is presented as complete or ready. This does
not permit silently truncating history or splitting a source transaction.

### `rdf_migration_preflight_cancelled`

The read-only inventory observed cancellation and drops its request-owned I/O
future. It writes no graph, receipt, activation or migration state. Start a new
bounded observation when appropriate; the cancelled read is not a readiness
receipt.

## Inactive JSON mutation preparation

These codes belong to the internal `records/1` write adapter. They do not imply
that a public write route, support activation or populated graph conversion is
available. The complete request is refused; no partial mutation is accepted.

### `record_payload_invalid`

The body is not valid JSON, is not an object, or contains a field/selector with
an invalid shape. Supply the strict versioned record request. Values are not
silently repaired or converted to another input format.

### `record_payload_ambiguous`

A versioned record request also supplies legacy commit fields, even with empty
values, or repeats a JSON object key, including inside field maps or term
envelopes. Use one contract and one value per key; the adapter does not guess
which duplicate value to keep.

### `unknown_field`

A record request, entry or conditions object has an unrecognized field. Correct
the field name instead of relying on it being ignored. Explicit terms and schema
properties still use their documented maps and selectors.

### `record_mutation_empty`

The request or one of its entries specifies no supported mutation. Omitted
fields preserve existing state. An explicitly authorized empty complete scope
replacement is distinct and remains a valid scope clear.

### `record_value_not_supported`

A value has no safe declared scalar mapping or supported exact RDF envelope,
or explicitly sets a control/identity to null. Supply an exact supported term
or a schema-declared scalar; null is not omission and unsafe numbers are not
rounded. The separate storage-term gate still applies.

### `record_relationship_incomplete`

A relationship supplies only part of its tuple. Supply source, type and target
together, or omit the complete tuple when making a supported patch to an existing
claim in the authorized scope.

### `assertion_support_not_found`

A partial relationship patch has no current claim in the selected owner/scope.
Another owner's claim does not grant edit authority or supply omitted state.
Use the intended authorized scope or provide a complete supported new claim.

### `record_scope_forbidden`

The requested owner/scope does not match the current integration grant. Body
fields cannot grant authority. Use the authorized scope; changing the request
key does not alter access rights.

### `record_owned_write_unsupported`

The versioned records adapter does not yet accept a hosted `owned_write` grant.
Use the existing hosted owned-write contract until its records adapter is
qualified. Changing the owner field or request key cannot widen the grant.

### `record_scope_replacement_incomplete`

A complete scope replacement contains partial field/relationship edits or omits
required desired state. Supply the complete desired set, including relationship
tuples and explicit asserted state. Do not split one intended replacement into
partial successful transactions.

### `record_response_budget`

The complete original acceptance receipt would exceed its 64 KiB bound. The
adapter refuses before immutable RDF/support uploads and never truncates IDs or
response fields. Reduce the intended request's response size while preserving
its required atomic scope.

## Current status selection

### `status_version_unsupported`

400 · `invalid_request_error`

Use `version=status/1` for bounded current RDF/class diagnostics. An unsupported
status version is refused. The temporary `version=legacy` selector follows the
finite unified API compatibility transition; it is not a permanent default.

### `status_parameter_ambiguous`

400 · `invalid_request_error`

Repeated status query parameters disagree. Send each selector once.

### `status_parameter_unsupported`

400 · `invalid_request_error`

`status/1` never inspects legacy indexes. Remove `include_legacy_indexes`; during
the compatibility window select `version=legacy` separately if needed.

## Current RDF demo selection

### `demo_version_unsupported`

400 · `invalid_request_error`

Use `version=demo/1` for pinned RDF fixture checks. An unsupported version is
refused. Explicit `version=legacy` follows the finite one-contract-generation
unified API compatibility window.

### `demo_parameter_ambiguous`

400 · `invalid_request_error`

Repeated versioned demo query parameters disagree. Send each selector once.

### `demo_parameter_unsupported`

400 · `invalid_request_error`

`demo/1` accepts only dataset, version and standard resource-scope selectors.
The previously ignored `source` option does not compare persisted and ephemeral
execution. Remove it; the current run checks one pinned RDF publication.

## Dedicated Update support admission

These errors apply to the unreleased opt-in binding on POST `/update` and its
`/api/update` and `/v1/update` aliases. Selection requires the original explicit
URL `expected_graph_epoch` and an explicit `Idempotency-Key`; it never creates or
converts a graph or activates support. Availability still requires a matching
server and an already valid support-enabled graph. This catalog does not add an
SDK helper, OpenAPI route, capability flag or production activation mechanism.

### `rdf_update_parameter_ambiguous`

400 · `invalid_request_error`

The selected Update repeats a decoded query control, supplies conflicting graph
or branch aliases, repeats a sensitive authentication/version/idempotency/framing
header, or repeats the form `update` field. Send every selector/header once and
one update source. The whole request is refused; do not retry it without the
original epoch selector or replace its original idempotency key.

### `rdf_update_parameter_unknown`

400 · `invalid_request_error`

The selected Update contains an unsupported URL or form control. The URL accepts
only existing graph, branch, environment and epoch selectors. A selected form
accepts exactly one `update` field, with no `query`, dataset, owner or dry-run
controls. Remove the unsupported field while preserving the intended mutation,
original graph incarnation and idempotency identity.

### `rdf_update_binding_unsupported`

400 · `invalid_request_error`

The selected dedicated Update requires `application/sparql-update` with raw
source or `application/x-www-form-urlencoded` with one `update` field. Correct
`Content-Type` and its matching body. The binding accepts `INSERT DATA`,
`DELETE DATA`, ground templates with an empty `WHERE`, `DELETE WHERE` of one
subject and predicate, and the `OPTIONAL` replacement of one subject and
predicate. It does not enable combined `/sparql` or Graph Store Protocol
mutations on support graphs.

### `rdf_update_payload_invalid`

400 · `invalid_request_error`

The selected Update is missing a nonempty source, has invalid form percent
escapes/UTF-8, or lacks its required explicit epoch at the handler boundary.
Supply a valid source and retain the original epoch/key for an ambiguous earlier
outcome. SPARQL syntax, unsupported algebra, RDF term and budget refusals keep
their existing separate error codes; malformed input never selects legacy
bootstrap as a fallback.

## Explicit bounded RDF import

The existing import route's strict support binding is selected by the presence
of `expected_graph_epoch`. It requires the original epoch and `Idempotency-Key`;
there is no fallback to ordinary bulk import. These refusals occur before
acceptance. After an unknown transport outcome, retry the exact original
semantic source with that same epoch/key; never remove the selector to retry.

### `rdf_import_parameter_ambiguous`

400 · `invalid_request_error`

A selected import repeats a query/authentication/framing header or
uses conflicting graph/branch aliases. Keep one unambiguous value per control.
No import is accepted.

### `rdf_import_parameter_unknown`

400 · `invalid_request_error`

The selected binding accepts only graph/branch/environment controls,
`expected_graph_epoch` and an optional N-Triples `format` alias. Bulk controls
such as `batch`, `build`, `strict`, `base_iri`, `graph_uri`, `blank_node_scope`,
`observed_at` and explicit scopes are unsupported. Remove unsupported controls;
never retry this request through the ordinary arm to bypass a refusal.
A URL owner is separately refused by existing 403 `owner_reserved` authority.

### `rdf_import_binding_unsupported`

400 · `invalid_request_error`

Selected import requires `application/n-triples` with one optional
UTF-8 charset and optional equivalent `format=nt|ntriples|n-triples`. Turtle,
N-Quads, TriG and other media parameters are unsupported in this bounded slice.
The ordinary unselected bulk route keeps its existing format support.

### `rdf_import_payload_invalid`

400 · `invalid_request_error`

The selected N-Triples source is empty or malformed, or the explicit
epoch is missing at its trusted binding seam. The entire source is refused;
valid earlier statements are not partially accepted. Blank nodes, named-graph
input and truth-codec limitations retain their applicable typed refusal.

## Retired local search commands

### `legacy_search_retired`

CLI-only refusal: the legacy `lbb-testctl graph search`, `multi-search`,
`full-text inspect/search`, record `embeddings build/inspect/search`,
`search-eval` and `bench-compare` spellings accept their arguments but stop before
backend or request-file access. Existing main error handling exits nonzero;
this is not a new HTTP route/status. Use RDF queries or class-declared embeddings
over HTTP where appropriate; legacy fusion, BM25 and explicit record-vector
requests have no automatic conversion. Existing local SDKs need a matching older
binary to execute their historical local-search methods.

The optional Python0.33 source companion retains five local method signatures but
raises `LbbLocalSearchRetiredError` (`legacy_local_search_retired`) before temporary
files or subprocess work. Source/package publication remain separate gates.
