# Unified Search Platform Error Codes (Canonical Registry)

Date: 2026-03-01
Status: Frozen (Normative error registry)
Owner: API Governance / Search Fabric Platform

## 1. Purpose

This document is the canonical registry for `SF_*` error semantics: status class, retryability, precedence, and required detail keys used by Unified Search Platform / Search Fabric APIs and compatibility profiles.

Normative rules:
- Machine-readable error-code enum values live in `api/proto/searchfabric/v1/search_fabric.proto` as `ErrorCode`, and emitted `ErrorStatus.code` values MUST map 1:1 to the canonical `SF_*` registry entries in this document. `ERROR_CODE_UNSPECIFIED = 0` is a reserved invalid sentinel: it is not a canonical registry row, MUST NOT be emitted in `ErrorStatus.code`, and any received public payload carrying it is malformed contract drift.
- HTTP status, retryability, and semantic contract are defined only in this document.
- Other specs (`docs/compatibility/mysql-fulltext.md`, `docs/compatibility/elasticsearch.md`, `docs/compatibility/turbopuffer.md`, `docs/compatibility/tidb-enhancement.md`, `docs/specs/core/search-fabric-architecture.md`) may map scenarios to codes, but MUST NOT redefine code semantics.
- New codes MUST be added here first before being referenced by any other document.

## 2. Error Model

Error envelope (canonical fields):
- `code`: stable canonical `ErrorCode` enum value, for example `SF_INVALID_DOC_ID`; emitted values MUST be canonical `SF_*` registry rows and MUST NOT be `ERROR_CODE_UNSPECIFIED`
- `message`: human-readable explanation
- `retryable`: retry recommendation (`true`/`false`)
- `correlation_id`: canonical emitted correlation identifier; MUST be non-empty on every emitted error, echoes caller `RequestMeta.correlation_id` when provided, and otherwise MUST be service-generated
- the canonical protobuf contract models emitted `ErrorStatus.correlation_id` with machine-checkable non-empty validation; services MUST therefore treat empty emission as malformed output rather than a tolerated projection detail
- `context`: optional canonical typed machine-readable failure context; when the protobuf contract defines a matching typed branch, machine-readable consumers MUST treat it as authoritative over mirrored string diagnostics
- `diagnostics`: optional string diagnostics / compatibility projection layer

Determinism rule:
- Same request under the same system state MUST return the same status class and `code`.

## 2.1 Deterministic Precedence (When Multiple Violations Apply)

If one request simultaneously violates multiple rules, the system MUST pick exactly one error code by the tiered order below.
If multiple candidates exist in the same tier, pick the first listed code in that tier.
Vector dimension mismatch branches MUST emit `SF_VECTOR_DIMENSION_MISMATCH` (not `SF_UNSUPPORTED_OPTION`) when a schema-dimension mismatch is the selected candidate in precedence resolution.

1. Access control tier:
- `SF_UNAUTHORIZED`
- `SF_FORBIDDEN`

2. Profile/scope/ownership tier:
- `SF_UNSUPPORTED_ENDPOINT`
- `SF_UNSUPPORTED_OPTION`
- `SF_UNSUPPORTED_QUERY_FEATURE`
- `SF_UNSUPPORTED_SYNTAX`
- `SF_UNSUPPORTED_PARSER`
- `SF_UNSUPPORTED_BOOLEAN_OPERATOR`
- `SF_UNSUPPORTED_TABLE_OPERATION`
- `SF_UNSUPPORTED_ENHANCEMENT_FEATURE`
- `SF_PARTITIONED_TABLE_UNSUPPORTED`
- `SF_OWNERSHIP_CONFLICT`

3. Contract/resource tier:
- `SF_INDEX_TARGET_REQUIRED`
- `SF_INVALID_NDJSON_BULK`
- `SF_INVALID_ARGUMENT`
- `SF_INVALID_SCHEMA`
- `SF_INVALID_DOC_ID`
- `SF_DOC_ID_CONTRACT_VIOLATION`
- `SF_MATCH_COLUMN_MISMATCH`
- `SF_INVALID_AGAINST_EXPRESSION`
- `SF_RESOURCE_NOT_FOUND`
- `SF_DOC_NOT_FOUND`
- `SF_SCHEMA_VIOLATION`
- `SF_VECTOR_DIMENSION_MISMATCH`

4. Limits/admission tier:
- `SF_PAYLOAD_TOO_LARGE`
- `SF_TOO_MANY_OPERATIONS`
- `SF_TOPK_TOO_LARGE`
- `SF_RATE_LIMITED`

5. Runtime/dependency/conflict tier:
- `SF_QUERY_TIMEOUT`
- `SF_VISIBILITY_TIMEOUT`
- `SF_CATALOG_UNAVAILABLE`
- `SF_BACKEND_UNAVAILABLE`
- `SF_IDEMPOTENCY_CONFLICT`
- `SF_VERSION_CONFLICT`
- `SF_DEBUG_DIGEST_MISMATCH`

6. Generic fallback tier:
- `SF_BAD_REQUEST`
- `SF_INVALID_QUERY`
- `SF_INTERNAL`

## 2.2 Canonical Detail-Key Registry

Mandatory string diagnostic keys are defined here and referenced by other specs.

Typed recurring machine-readable failure semantics are owned first by `ErrorStatus.context` when the canonical protobuf contract defines a matching branch. `ErrorStatus.diagnostics` remains the canonical string-diagnostic/projection layer for:
- compatibility/header/body mirroring,
- deterministic textual hints for string-only consumers,
- failure families that do not yet define a typed `ErrorStatus.context` branch.

Encoding rule for `ErrorStatus.diagnostics` (`map<string, string>`):
- all detail values are canonical strings on the protobuf wire.
- numeric values MUST use base-10 ASCII string encoding with no extra formatting.
- repeated-field/set diagnostics MUST use one deterministic encoding defined by the owning key; callers and compatibility gateways MUST NOT invent per-implementation encodings.

Projection rule:
- when both `ErrorStatus.context` and `ErrorStatus.diagnostics` are populated for the same semantic branch, machine-readable protobuf consumers MUST treat `context` as authoritative.
- `diagnostics` MAY mirror subsets of typed `context` fields for compatibility projection, logging, or string-only consumers.

1. Unsupported/complex query-feature rejection (`SF_UNSUPPORTED_QUERY_FEATURE` / `SF_UNSUPPORTED_OPTION`):
- `unsupported_feature`
- `normalized_path`
- `fallback_hint`
- Primary typed context branch: `ErrorStatus.context.query.unsupported_feature`.
- strict aggregation-depth branch additionally requires:
  - `requested_aggregation_depth`
  - `max_aggregation_depth`

2. Result-window limit rejection (`SF_TOO_MANY_OPERATIONS`, max-result-window branch):
- `limit_scope` (value: `max_result_window`)
- `max_result_window` (the resolved effective window bound after control-plane default resolution, not the raw optional schema field)
- `requested_offset`
- `requested_limit`
- `requested_window`
- Typed context projection uses `ErrorStatus.context.query.limit_rejection` with:
  - `limit_scope=max_result_window`
  - `configured_limit=<max_result_window>`
  - `requested_offset`
  - `requested_limit`
  - `requested_window`

3. Selector-materialization probe clamp rejection (`SF_TOO_MANY_OPERATIONS`):
- `limit_scope` (value: `selector_materialization_limit`)
- `configured_limit` (the actual admitted cutoff after applying `caller_requested_limit`, `max_entries_per_batch`, and `effective_max_result_window`; equivalently `probe_limit - 1`)
- `requested_value`
- `effective_constraint_source` (value: `max_entries_per_batch` or `max_result_window`; this field identifies the smallest owner-managed internal bound participating in the clamp and MUST NOT use `caller_requested_limit` as a third value)
- Typed context projection uses `ErrorStatus.context.query.limit_rejection` with:
  - `limit_scope=selector_materialization_limit`
  - `configured_limit`
  - `requested_value`
  - `effective_constraint_source`

4. Dynamic payload/window budget rejection (`SF_PAYLOAD_TOO_LARGE` or `SF_TOO_MANY_OPERATIONS`):
- `limit_scope` (value: `dynamic_payload_budget` or `dynamic_result_window`)
- `effective_limit`
- `requested_bytes` (payload branch)
- `requested_window` (window branch)
- Primary typed context branch: `ErrorStatus.context.query.limit_rejection`.
- Typed context projection uses:
  - payload branch: `limit_scope=dynamic_payload_budget`, `effective_limit`, `requested_bytes`
  - window branch: `limit_scope=dynamic_result_window`, `effective_limit`, `requested_window`

5. Rate-limit / runtime cost-governor rejection (`SF_RATE_LIMITED`):
- `retry_after_ms`
- `throttled_dimension`
- `server_limit`

6. Vector dimension mismatch (`SF_VECTOR_DIMENSION_MISMATCH`):
- `expected_dimensions`
- `actual_dimensions`

7. Internal debug digest mismatch (`SF_DEBUG_DIGEST_MISMATCH`):
- `gateway_normalized_digest`
- `service_attested_digest`
- `digest_algorithm`

8. Operation-budget rejection (`SF_TOO_MANY_OPERATIONS`, depth/batch/allocator-guardrail branches):
- `limit_scope` (value: `max_page_depth`, `max_entries_per_batch`, `max_in_list_elements`, `max_predicate_ast_nodes`, `allocator_plan_items`, `allocator_forward_reservation_window`, or `allocator_identity_space_remaining`)
- `configured_limit`
- `requested_value`
- `field` (required when `limit_scope=max_in_list_elements`)
- Primary typed context branch:
  - query-family branches -> `ErrorStatus.context.query.limit_rejection`
  - allocator guardrail branches -> `ErrorStatus.context.allocator.limit_rejection`
- allocator guardrail projection rules:
  - `allocator_plan_items`: `configured_limit` is the admitted maximum `AllocateIdsRequest.plan.items[]` cardinality and `requested_value` is the received plan-item count
  - `allocator_forward_reservation_window`: `configured_limit` is the admitted maximum forward-reservation jump from the current allocator watermark and `requested_value` is the jump required by the rejected explicit plan item
  - `allocator_identity_space_remaining`: `configured_limit` is the remaining allocatable `uint64` document-ID count in the collection-local allocator space at admission time and `requested_value` is the additional identity count required by the rejected issuance/reservation step

9. Flow-A schema-generation boundary rejection (`SF_VERSION_CONFLICT`):
- `invalidated_at_commit_ts`
- Primary typed context branch: `ErrorStatus.context.ingest_schema_boundary_invalidation.invalidated_at_commit_ts`.

10. Optimistic-precondition conflict (`SF_VERSION_CONFLICT`, compare-and-set branch):
- `doc_id`
- `expected_commit_ts`
- `latest_commit_ts`

11. Control-plane lifecycle admission conflict (`SF_VERSION_CONFLICT`, lifecycle/name-reservation branch):
- `lifecycle_state`
- `reservation_scope` (for example `namespace_child_collection_allocation`, `namespace_name`, `collection_name`, `resolved_namespace_lineage`, or `resolved_collection_lineage`)
- `reservation_release_at_unix_ms` (required for tombstoned-name reservation branches; decimal string carrying the absolute reservation-release timestamp in Unix milliseconds, not a relative delay)
- `drop_revision` (required for collection tombstone reservation branches)
- Metadata-mutation lifecycle-conflict invariants for these registry branches are tracked by `docs/testing/api-contract-conformance-matrix.md` invariant `SF-CONF-CATALOG-002`.

12. Descriptor-completeness unavailable (`SF_CATALOG_UNAVAILABLE`):
- `descriptor_state`
- `missing_descriptor_fields` (`field_a,field_b,...` comma-separated field names sorted ascending; when projected from `DescriptorPublishing.missing_fields[]`, it MUST preserve that same canonical ordered list)
- Primary typed context branch: `ErrorStatus.context.descriptor_publishing_unavailable`.
- Descriptor completeness / missing-fields invariants for this registry branch are tracked by `docs/testing/api-contract-conformance-matrix.md` invariant `SF-CONF-CATALOG-001`.

13. Schema-bootstrap unavailable (`SF_CATALOG_UNAVAILABLE`):
- `catalog_unavailable_reason` (value: `schema_bootstrap`)
- `schema_bootstrap_state` (value: `no_active_schema_generation`)
- Primary typed context branch for query-family failures: `ErrorStatus.context.query.catalog_unavailable.schema_bootstrap`.
- Primary typed context branch for allocator-family failures: `ErrorStatus.context.allocator.catalog_unavailable.schema_bootstrap`.
- Non-query admission surfaces that fail for the same missing-active-schema condition MUST reuse the same canonical diagnostics values even when a route-specific typed branch differs from the query-family carrier.

14. Schema-convergence unavailable (`SF_CATALOG_UNAVAILABLE`):
- `catalog_unavailable_reason` (value: `schema_convergence`)
- `schema_convergence_state` (value: `no_ready_serving_generation`)
- Primary typed context branch for query-family failures: `ErrorStatus.context.query.catalog_unavailable.schema_convergence`.

15. Statistics-freshness unavailable (`SF_CATALOG_UNAVAILABLE`):
- `catalog_unavailable_reason` (value: `statistics_freshness`)
- `max_staleness_ms`
- `latest_stats_commit_ts`
- `latest_stats_collected_at_unix_ms`
- Primary typed context branch: `ErrorStatus.context.query.catalog_unavailable.statistics_freshness`.

16. Query/read-side strict snapshot visibility timeout (`SF_VISIBILITY_TIMEOUT`, exact-snapshot branch):
- `required_read_ts`
- `effective_read_ts`
- `safe_ts`
- Primary typed context branch: `ErrorStatus.context.query.visibility_timeout`.

17. Query/read-side bounded-staleness visibility timeout (`SF_VISIBILITY_TIMEOUT`, lag-breach branch):
- `required_read_ts`
- `effective_read_ts`
- `safe_ts`
- `max_staleness_ms`
- `actual_lag_ms`
- Primary typed context branch: `ErrorStatus.context.query.visibility_timeout`.

18. Query serving-generation/token conflict (`SF_VERSION_CONFLICT`):
- `expected_schema_generation_token` (required when the rejected request or token chain fenced on a concrete serving generation)
- `conflict_source` (value: `expected_schema_generation_token`, `continuation_page_token`, `composite_page_token`, or `search_context_token`)
- Primary typed context branch: `ErrorStatus.context.query.schema_version_conflict`.
- Typed context projection uses `ErrorStatus.context.query.schema_version_conflict` with:
  - `expected_schema_generation_token`
  - enum-valued `conflict_source` mirrored into canonical diagnostics string value
- Deterministic precedence rule for `conflict_source`:
  - direct request fencing drift -> `expected_schema_generation_token`
  - continuation carrying `continuation_page.next_page_token` -> `continuation_page_token`
  - composite continuation carrying `composite_page.next_page_token` -> `composite_page_token`
  - search-context-only continuation / PIT drift without a page token -> `search_context_token`
- therefore when continuation carries both page and search-context token families and both fence the same stale serving generation, the canonical projection MUST use the page-token branch for that request shape (`continuation_page_token` for any request carrying `continuation_page.next_page_token`, including unary continuation and `StreamQuery` resume; `composite_page_token` for composite continuation)

19. Mutation-stream reconnect restart checkpoint (`SF_BACKEND_UNAVAILABLE` or `SF_INVALID_QUERY`, replay-restart branch):
- `restart_commit_ts` (decimal string)
- `restart_source_partition` (canonical `source_partition` string as admitted on the stream contract)
- `restart_source_epoch` (decimal string)
- `restart_source_seq` (decimal string)

20. Allocator explicit-ID reservation conflict (`SF_VERSION_CONFLICT`):
- `doc_id`
- `allocator_conflict_reason` (value: `below_watermark_burned_gap`)
- Primary typed context branch: `ErrorStatus.context.allocator.reservation_conflict`.
- Typed context projection uses `ErrorStatus.context.allocator.reservation_conflict` with:
  - `doc_id`
  - enum-valued `conflict_reason=ALLOCATOR_RESERVATION_CONFLICT_REASON_BELOW_WATERMARK_BURNED_GAP`
- In the active dense-burn allocator model, this value is selected whenever a fresh explicit reservation names any `doc_id < next_doc_id`, including IDs previously issued/reserved and IDs skipped by earlier watermark advancement or discarded lease tail.

21. Allocator receipt-validation rejection (`SF_BAD_REQUEST` or `SF_FORBIDDEN`):
- `receipt_validation_reason` (value: `missing_required_receipt`, `malformed_receipt`, `signature_invalid`, `expired_receipt`, `caller_mismatch`, `scope_mismatch`, `realized_doc_ids_mismatch`, `route_intent_mismatch`, or `schema_generation_token_mismatch`)
- Primary typed context branch: `ErrorStatus.context.allocator.receipt_validation`.
- Typed context projection uses `ErrorStatus.context.allocator.receipt_validation.reason` mirrored into the canonical diagnostics string value above.
- Deterministic code-selection rule for this family:
  - `caller_mismatch` -> `SF_FORBIDDEN`
  - every other listed allocator-receipt validation reason -> `SF_BAD_REQUEST`

Canonical lifecycle-conflict branch mapping:

| Admission branch | `lifecycle_state` | `reservation_scope` | `reservation_release_at_unix_ms` | `drop_revision` |
|---|---|---|---|---|
| child collection allocation rejected because namespace is `QUIESCING` | `QUIESCING` | `namespace_child_collection_allocation` | absent | absent |
| child collection allocation rejected because namespace is `TOMBSTONED` | `TOMBSTONED` | `namespace_child_collection_allocation` | required; absolute namespace-name reservation release timestamp (`lifecycle_gc_after_unix_ms`) | absent |
| same-name namespace recreation rejected because namespace name is still reserved by a tombstoned namespace | `TOMBSTONED` | `namespace_name` | required; absolute namespace-name reservation release timestamp (`lifecycle_gc_after_unix_ms`) | absent |
| same-name collection recreation rejected because collection name is still reserved by a tombstoned collection | `TOMBSTONED` | `collection_name` | required; absolute collection-name reservation release timestamp (`gc_after_unix_ms`) | required; tombstone `drop_revision` |
| resolved namespace metadata update loses the stable-id-owned apply race to a conflicting namespace-lineage transition and the namespace is now `QUIESCING` | `QUIESCING` | `resolved_namespace_lineage` | absent | absent |
| resolved namespace metadata update loses the stable-id-owned apply race to a conflicting namespace-lineage transition and the namespace is now `TOMBSTONED` | `TOMBSTONED` | `resolved_namespace_lineage` | required; absolute namespace-name reservation release timestamp (`lifecycle_gc_after_unix_ms`) | absent |
| resolved collection metadata update loses the stable-id-owned apply race to a terminal collection-lineage transition | `TOMBSTONED` | `resolved_collection_lineage` | required; absolute collection-name reservation release timestamp (`gc_after_unix_ms`) | required; tombstone `drop_revision` |

Normative rules for this table:
- Implementations MUST emit exactly the detail-key set and value semantics bound above for the listed branches.
- `reservation_release_at_unix_ms` MUST be encoded as base-10 Unix milliseconds and MUST NOT be interpreted as a relative remaining duration.
- Branches not listed above MUST NOT invent new `reservation_scope` values without first updating this registry.

## 2.3 Protocol Error Projection Rules

Canonical precedence and code selection are always decided first (Sections `2.1` and `3`), then projected onto one of two surfaces:
- canonical protobuf/gRPC response envelopes
- compatibility HTTP/JSON route shapes

1. Canonical protobuf/gRPC surface:
- MUST emit canonical `ErrorStatus` envelope (`code`, `message`, `retryable`, `correlation_id`, optional typed `context`, optional string `diagnostics`) on the canonical protobuf/gRPC error surface owned by `docs/specs/core/search-fabric-api.md`.
- Depending on the owning RPC family, that surface is either:
  - the declared protobuf response carrier error branch, or
  - non-`OK` gRPC status details carrying the canonical `ErrorStatus`.
- `ErrorStatus.code` MUST carry the canonical `ErrorCode` enum value that corresponds 1:1 to the selected registry row in Section `3`, and MUST NOT carry `ERROR_CODE_UNSPECIFIED`.

2. Elasticsearch-compatibility routes:
- MUST emit Elasticsearch-native error envelope:
  - top-level: `status`
  - object: `error.type`, `error.reason`, `error.root_cause[]`
- canonical `SF_*` code and `correlation_id` MUST still be exposed deterministically via response headers:
  - `X-SF-Code: <canonical SF_*>`
  - `X-SF-Correlation-Id: <canonical correlation_id>`
- when projecting protobuf `ErrorCode` onto compatibility headers, gateways MUST emit the exact enum symbolic identifier string (for example `SF_RESOURCE_NOT_FOUND`), not the numeric enum value or implementation-local formatting.
- gateways MAY additionally mirror the same canonical diagnostics into Elasticsearch body extension fields such as `error.caused_by`, but headers are the required interoperability carrier.
- aggregation defensive rejection projection:
  - admission-time parse/shape/budget rejection -> `error.type=parsing_exception`
  - execution-time failure after admission -> `error.type=search_phase_execution_exception`

3. Elasticsearch `/_bulk` partial-success projection:
- syntactically valid bulk requests MUST return HTTP `200` with Elasticsearch bulk body shape (`errors`, `items[]`), even when some items fail.
- `errors=true` iff at least one item has failure status (`>=400`); otherwise `errors=false`.
- each item MUST carry Elasticsearch-compatible `status` and failure `error` payload.
- deterministic item-status mapping baseline:
  - canonical request/contract/schema violations -> `400`
  - not-found -> `404`
  - conflict (`SF_VERSION_CONFLICT`, `SF_IDEMPOTENCY_CONFLICT`, `SF_OWNERSHIP_CONFLICT`, `SF_DEBUG_DIGEST_MISMATCH`) -> `409`
  - throttling -> `429`
  - backend/timeout -> `503`/`504`

429 compatibility projection rule (applies to every compatibility-route projection of `SF_RATE_LIMITED`):
- gateways MUST emit:
  - `Retry-After` header (seconds form)
  - `X-RateLimit-Limit`
  - `X-RateLimit-Remaining`
  - `X-RateLimit-Reset`
  - `X-SF-Throttled-Dimension`
- when the route body shape admits structured diagnostics, gateways SHOULD also mirror deterministic retry hints in the body/details layer using the canonical detail keys:
  - `retry_after_ms`
  - `throttled_dimension`
  - `server_limit`

4. Turbopuffer OpenAPI-parity routes:
- MUST emit Turbopuffer `ErrorResponse` (`status`, `error`) without extra canonical envelope fields in the JSON body.
- canonical `SF_*` code and `correlation_id` MUST still be exposed deterministically via response headers:
  - `X-SF-Code: <canonical SF_*>`
  - `X-SF-Correlation-Id: <canonical correlation_id>`
- when projecting protobuf `ErrorCode` onto compatibility headers, gateways MUST emit the exact enum symbolic identifier string (for example `SF_RESOURCE_NOT_FOUND`), not the numeric enum value or implementation-local formatting.
- these headers are mandatory on all Turbopuffer-parity error responses because upstream OpenAPI `ErrorResponse` has no body slot for canonical correlation metadata.

## 3. Canonical Code Registry

| HTTP | Code | Retryable | Semantic Contract |
|---|---|---|---|
| 400 | `SF_BAD_REQUEST` | No | Generic malformed request framing/syntax/payload-envelope violation (for example invalid NDJSON shape, malformed token envelope, structurally broken source wire body outside typed canonical carrier semantics, an invalid framing-level enum sentinel such as `MutationBatch.policy.durability=DURABILITY_POLICY_UNSPECIFIED`, `MutationBatch.policy.visibility=VISIBILITY_POLICY_UNSPECIFIED`, or `MutationBatch.policy.ingest_mode=INGEST_MODE_UNSPECIFIED`, an invalid admitted write-policy combination such as `MutationBatch.policy.ingest_mode=INGEST_MODE_BATCH` paired with `MutationBatch.policy.visibility=VISIBILITY_POLICY_ASYNC` or `MutationBatch.policy.durability=DURABILITY_POLICY_WAL_CHUNK_DURABLE`, or allocator-receipt validation failure whose canonical `receipt_validation_reason` is not `caller_mismatch`). |
| 400 | `SF_INVALID_ARGUMENT` | No | Structurally empty strongly-typed carrier or request-side present-but-empty typed carrier payloads. Missing required scalar/string fields and generic framing/token-envelope malformation remain `SF_BAD_REQUEST`. Enum-zero classification is semantic-context-dependent in this revision: request/query enum-zero branches may map to `SF_INVALID_QUERY`, schema/config enum-zero branches may map to `SF_SCHEMA_VIOLATION` or `SF_INVALID_SCHEMA`, and only framing-level malformed enum branches remain `SF_BAD_REQUEST`. |
| 400 | `SF_INVALID_QUERY` | No | Operation-contract semantics are invalid for the admitted operation (for example invalid/expired query continuation or search-context token on query execution/continuation paths, ingest/snapshot reconnect token expiry on branches mapped to this code, or query structure outside active profile). Snapshot upload resume-token expiry is canonicalized here; caller recovery is to start a fresh `StartSnapshotSync` session because used sessions do not admit tokenless resume in this revision. |
| 400 | `SF_INVALID_SCHEMA` | No | Schema declaration is malformed or violates schema-admission contract before canonical apply (for example unknown / out-of-contract `DocIDMapping.source_field_type` enum value). |
| 400 | `SF_INVALID_DOC_ID` | No | wire-level external `doc_id`/`id` value cannot be losslessly normalized into canonical `uint64` / 64-bit unsigned integer form from an admitted active-profile representation (for example decimal string token or non-negative integer numeric token), or is out of range. |
| 400 | `SF_DOC_ID_CONTRACT_VIOLATION` | No | Configured or onboarded canonical `doc_id` source violates the active `DocIDMapping` contract (including schema-admission requests that choose an admitted-but-disallowed `source_field_type` such as `STRING`/`BYTES`, or runtime type/uniqueness/immutability violations), or a mutation attempts to modify an immutable canonical `doc_id` source after insert. |
| 400 | `SF_UNSUPPORTED_ENDPOINT` | No | Endpoint/method is outside declared compatibility scope. |
| 400 | `SF_UNSUPPORTED_OPTION` | No | Request option/parameter/field is outside declared compatibility subset. |
| 400 | `SF_UNSUPPORTED_QUERY_FEATURE` | No | Query feature is outside declared compatibility subset. |
| 400 | `SF_UNSUPPORTED_SYNTAX` | No | SQL/FTS syntax form is outside declared compatibility scope. |
| 400 | `SF_UNSUPPORTED_PARSER` | No | Parser option is outside declared compatibility scope. |
| 400 | `SF_UNSUPPORTED_BOOLEAN_OPERATOR` | No | Boolean operator/token pattern is unsupported. |
| 400 | `SF_UNSUPPORTED_TABLE_OPERATION` | No | Table-level operation, or table-scoped schema/control-plane capability, is unsupported for the active profile/phase. This includes active-revision federated-table SQL operations that require TiKV-backed local transaction/locking semantics (for example mixed local+federated write transactions, locking reads, unsupported multi-statement transaction writes, or non-lowerable wide-scope write forms). |
| 400 | `SF_UNSUPPORTED_ENHANCEMENT_FEATURE` | No | TiDB enhancement feature is outside active profile scope. |
| 400 | `SF_PARTITIONED_TABLE_UNSUPPORTED` | No | Partitioned-table behavior requested outside the supported phase/profile window. |
| 400 | `SF_MATCH_COLUMN_MISMATCH` | No | `MATCH()` column list does not match a declared `FULLTEXT` index definition. |
| 400 | `SF_INVALID_AGAINST_EXPRESSION` | No | `AGAINST()` expression is not constant during query evaluation. |
| 400 | `SF_INVALID_NDJSON_BULK` | No | Bulk NDJSON payload is malformed. |
| 400 | `SF_INDEX_TARGET_REQUIRED` | No | Required index target is missing. |
| 400 | `SF_TOO_MANY_OPERATIONS` | No | Request exceeds a configured operation/window/depth/allocation budget (for example batch operation count, `max_result_window`, page-depth ceilings, oversized `IN` predicate cardinality, predicate-AST complexity ceilings, allocator request-item ceiling, allocator forward-reservation window, or allocator identity-space remaining budget). |
| 400 | `SF_TOPK_TOO_LARGE` | No | Requested top-K exceeds configured/profile limit. |
| 401 | `SF_UNAUTHORIZED` | No | Authentication failed or missing credentials. |
| 403 | `SF_FORBIDDEN` | No | Authenticated caller lacks required access to namespace/collection/API. This also covers allocator-receipt validation failure where a structurally valid receipt is bound to a different authenticated caller (`receipt_validation_reason=caller_mismatch`). |
| 404 | `SF_RESOURCE_NOT_FOUND` | No | Target canonical resource does not exist for the requested operation (for example namespace, collection/index/table, or another addressed catalog/runtime resource). |
| 404 | `SF_DOC_NOT_FOUND` | No | Target document does not exist for the requested operation. |
| 409 | `SF_IDEMPOTENCY_CONFLICT` | No | Same idempotency key used with different payload, or reconnect/session resume token binding conflicts where token-bound cursor/session payload does not match admitted stream/session state. |
| 409 | `SF_VERSION_CONFLICT` | No | Query-serving schema-generation/token fence conflict, version/create-only conflict for a target document, allocator explicit-ID reservation conflict on a collection-local dense-burn identity space, or transaction/configuration/lifecycle state conflict that violates deterministic invariants. |
| 409 | `SF_DEBUG_DIGEST_MISMATCH` | No | Internal debug digest attestation mismatch: gateway-normalized payload digest differs from service-attested digest for the same debug probe input. |
| 409 | `SF_OWNERSHIP_CONFLICT` | No | Request violates the authoritative `collection_truth_mode` admission policy or a route/caller policy derived from it. This includes directing native search write routes at `COLLECTION_TRUTH_MODE_EXTERNAL` collections, or directing TiCDC/TiDB-owned projection paths at `COLLECTION_TRUTH_MODE_SEARCH_FABRIC` collections. |
| 413 | `SF_PAYLOAD_TOO_LARGE` | No | Request payload exceeds configured size limit. |
| 422 | `SF_SCHEMA_VIOLATION` | No | Payload/schema/type violates table or profile schema constraints. |
| 422 | `SF_VECTOR_DIMENSION_MISMATCH` | No | Vector dimension does not match table schema. |
| 429 | `SF_RATE_LIMITED` | Yes | Request rejected or pre-empted by tenant/API throttling, admission quota, adaptive load shedding, or runtime cost enforcement. |
| 503 | `SF_CATALOG_UNAVAILABLE` | Yes | Catalog/descriptor state is temporarily unavailable for ownership/schema/metadata validation, or serving/bootstrap state is not yet admissible (for example descriptor publication remains incomplete, a collection exists but no active schema generation has been admitted yet, allocator admission cannot obtain required authoritative write-admission facts, or query serving has no `READY` generation yet). |
| 503 | `SF_BACKEND_UNAVAILABLE` | Yes | Required backend/dependency is temporarily unavailable, including control-path dependencies such as quota-refill / lease-bootstrap authority for gateway admission, write-side `wait_for_visible` deadline expiry before publish completes, or retry requires restarting from a supplied checkpoint because prior replay/resume state is no longer retained. |
| 504 | `SF_QUERY_TIMEOUT` | Yes | Query execution exceeded configured timeout. |
| 504 | `SF_VISIBILITY_TIMEOUT` | Yes | Query/readiness visibility waiting exceeded configured timeout, including read-side snapshot visibility waiting and read-side freshness/staleness admission waiting. |

- Batch-lane policy / atomicity error branches for this registry are tracked by `docs/testing/api-contract-conformance-matrix.md` invariant `SF-CONF-INGEST-001`.
- Snapshot session binder / resume error branches for this registry are tracked by `docs/testing/api-contract-conformance-matrix.md` invariant `SF-CONF-SNAPSHOT-001`.
| 500 | `SF_INTERNAL` | No | Unclassified internal server failure. |

## 4. Change Management

- Additive evolution: introducing new codes is allowed only with backward-compatible rollout notes.
- Breaking evolution: changing HTTP status or semantic contract of an existing code requires architecture-review approval and migration notes in all dependent profile docs.
- Deprecation: deprecated codes MUST remain documented until all referencing profiles remove usage.
