Skip to content
Talk to our solutions team

Error codes

data.svc returns 64 distinct code values on its main API surface, 21 more on the worksheet surface, and no code at all on the admin plane. This page is the complete list. Branch on code, not on the status: several codes carry a status that is chosen at response time from the underlying error.

Three shapes, and one route class that is not JSON at all.

SurfaceBody
Main API (/data/rest/*, /data/anon/rest/*, /data/schema/*, /data/actions/*, /data/x/*, /data/stateflow*, /data/bulk, /data/cache, /data/contentstore/list){"error":"<message>","code":"v2.<slug>","details":{...}}code and details omitted when empty
Worksheets (/data/worksheets/*){"error":{"code":"<area>.<slug>","message":"…","details":{…},"request_id":"…"}}error is an object
Admin plane (/data/admin/data/*, /data/superadmin/*){"error":"<message>"} — no code, no details
Authentication rejection (any protected route)Plain text Unauthorized, Content-Type: text/plain; charset=utf-8

details is populated on eight codes only:

Codedetails
v2.bulk_failedoperations — the partial per-operation result array
v2.rate_limitedprofile, limit, remaining, retry_after (seconds)
v2.action_method_not_allowedallowed — array of verbs
v2.method_not_allowedallowed — a single verb string, not an array
v2.file_storage_unconfiguredentity
v2.file_downloader_unconfiguredentity, id
v2.search_text_not_supportedentity, audit
v2.search_dsl_not_supportedentity, got — the Go type of the rejected filter — and audit

Six codes — v2.query_failed, v2.create_failed, v2.update_failed, v2.delete_failed, v2.restore_failed, v2.search_query_failed — name the operation that failed, not the reason. The status carries the reason, and is derived from the engine error:

Engine errorStatus
Access rule or row-level rule denied the operation403
Row or entity not found404
Field, entity or business-constraint validation failed422
Anything else500

Classification is by error type first. A substring fallback covers the paths that still return untyped errors: access denied / not authorised / not authorized / forbidden → 403, not found → 404, validation / invalid / is required → 422, everything else → 500.

CodeStatusMeaningLikely cause
v2.no_tenant403No tenant key was resolved into the request contextMissing or unroutable tenant headers, or the tenant is not configured on this deployment
v2.missing_tenant400The :tenant path parameter is required on this superadmin routeSuperadmin URL built without the tenant segment
v2.invalid_tenant400The :tenant value must be the bare tenant name, not a full four-part keyCustomer, product and environment come from the request, not the path
v2.bad_path400A required path segment is empty — entity, id, action name, or entity plus actionRequest against a route shape the handler does not recognise
CodeStatusMeaningLikely cause
v2.bad_json400The body is not valid JSON, or the bulk envelope failed to parseMalformed payload
v2.body_read400The body could not be read off the wireTruncated request, client disconnect, oversized body
v2.bad_params400Action parameters failed to bindUnreadable body, or invalid JSON in an action call
v2.missing_id400An update needs a primary key and none was suppliedPUT/PATCH /data/rest/{entity} with no key in the body and no /id/{id} in the path
v2.id_mismatch422The primary key in the body contradicts the one in the pathThe key is immutable; send it consistently or omit it
v2.bad_expression400The ?expression= program failed to compileSyntax error in the response-shaping expression
v2.expression_runtime500The expression compiled but failed at evaluation, or exceeded its time ceilingReference to a field absent from the result, or an illegal operation

Expression semantics are on request flags.

CodeStatusMeaningLikely cause
v2.entity_not_found404The entity is not in the tenant’s composed schemaTypo, or the definition was never loaded for this tenant and product
v2.row_not_found404No row with that idWrong id, or the row is soft-deleted and therefore invisible to reads
v2.missing_entity400No entity was supplied, as a path segment or as ?entity=Bulk import/export without ?entity=, or a schema route without the entity segment
v2.stateflow_not_found404No stateflow registered under that nameTypo, or the flow is not in the composed schema
v2.missing_name400The stateflow name path segment is emptyDetail route called with no name

v2.row_not_found after a successful DELETE is expected: delete is soft by default. See traits.

CodeStatusMeaningLikely cause
v2.query_failed403 / 404 / 422 / 500A read failed in the engineAccess denial, missing row, invalid filter, database error
v2.create_failed403 / 404 / 422 / 500A create failedValidation failure, unique or foreign-key violation, access denial
v2.update_failed403 / 404 / 422 / 500An update failedfinal / readonly / writeonce violation, validation failure, rejected state transition, access denial
v2.delete_failed403 / 404 / 422 / 500A delete failedForeign-key restriction from a child row, access denial
v2.restore_failed403 / 404 / 422 / 500A soft-delete restore failedMost often restore: entity %q has no soft-delete columns — the entity does not carry the trait
v2.search_query_failed403 / 404 / 422 / 500A structured search failedUnfilterable field, bad operator, access denial
v2.search_body_parse_failed400The search body is not decodable JSONMalformed body on POST /data/rest/{entity}/search
v2.search_text_not_supported501Free-text search is not implementedSending query instead of a filter object; no search client is wired
v2.search_dsl_not_supported501A filter supplied as a string is not interpretedSend filter as a JSON object

Operators and filter shapes are on query DSL; the per-rule failure messages are on validations and stateflows.

CodeStatusMeaningLikely cause
v2.empty_envelope400The operations array is empty or absentEnvelope posted with no operations
v2.bulk_failed422The bulk transaction rolled backAny operation failed; details.operations carries the partial results
v2.op_failedPer-operation code inside the response body, not a statusSet as error_code on the failing entry, alongside an error string
v2.bad_format400Unsupported import/export format?format= is not csv, json or jsonl (ndjson is accepted as an alias for jsonl)
v2.import_failed500A bulk import failed mid-streamMalformed source rows, type coercion failure, or a database error

The whole envelope runs in one transaction: one failure rolls everything back. The 422 body still carries the per-operation array for diagnostics — treat it as a report, not as a partial success.

CodeStatusMeaningLikely cause
v2.action_not_found404No action or query hash registered under that nameTypo, or the definition is not part of the tenant’s composed schema
v2.action_method_not_allowed405The action declares no section for this verbAn Allow header lists the accepted verbs and details.allowed repeats them
v2.action_failed500The action executed and erroredSQL error, script error, downstream call failure
v2.registry_unavailable500The query-hash registry could not be resolvedRegistry provider not wired, or tenant configuration incomplete

Parameter binding refusals surface as v2.action_failed with messages naming the parameter: unknown parameter, missing required parameter, value not in enum.

CodeStatusMeaningLikely cause
v2.endpoint_not_found404No endpoint at that path — including one that exists but is disabledA disabled endpoint deliberately answers 404, not 403, so its existence is not disclosed
v2.endpoint_path_missing404The dispatch catch-all matched with an empty pathRequest to the script root with no endpoint segment
v2.method_not_allowed405The endpoint declares one verb and the request used anotherAllow header and details.allowed name the expected verb
v2.unauthenticated401The endpoint requires a principal and none was resolvedMissing or expired token. This 401 is JSON — unlike the middleware’s
v2.forbidden403The endpoint’s auth gate rejected the principalPrincipal lacks what the endpoint requires; also returned for an unknown auth mode in the declaration
v2.bad_body400The body is unreadable, not JSON, or over 1 MiBBody shape does not match the endpoint’s declaration
v2.script_error500The script failed to compile, or threw at runtimeAny uncaught error in the endpoint body; also a file: script whose bytes were never inlined
v2.script_engine_missing500The endpoint registry was built without a script engineDeployment wiring bug. An unsupported language: does not land here — it is refused at registration, so the endpoint answers v2.endpoint_not_found

See scripted endpoints.

CodeStatusMeaningLikely cause
v2.file_storage_unconfigured501No file-storage backend is registeredAny multipart create
v2.file_downloader_unconfigured501No downloader is registeredAny ?download=true read
v2.multipart_parse400The multipart body could not be parsedBad boundary or truncated upload
v2.multipart_empty400Multipart parsed but produced no formUpload with no file and no fields
v2.multipart_bad_payload400A file part targets an undeclared field, targets a non-file field, carries more than one file for a field, or could not be readWrong field names, or an array upload against a single-file field
v2.download_needs_id400Download requires the /id/{id} form?download=true used on a list path
v2.missing_field400Download requires ?field=Field name omitted
v2.field_not_found404The field does not exist on the entityTypo
v2.field_not_file400The field is not file-typedDownload requested against a scalar
v2.field_empty404The file field exists but holds no reference on this rowNothing was ever uploaded
v2.field_unexpected_shape500The stored reference is present but not a stringData written outside the API, or a storage-format change
v2.download_failed500The byte stream could not be fetchedStorage outage, expired credentials, deleted object
v2.contentstore_list_failed500The content-store catalogue could not be readBacking store unavailable
CodeStatusMeaningLikely cause
v2.requires_admin403The route requires admin or superadminRole matching is case-insensitive, and superadmin also satisfies admin
v2.requires_superadmin403The route requires superadmin strictlyPlan apply, retention and lock force-release are superadmin-gated even for tenant admins
v2.rate_limited429The rate-limit bucket for this tenant, user and profile is exhaustedAnonymous traffic is rate-limited too

A v2.rate_limited response carries Retry-After plus X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.

One further code, v2.authz_denied (403), exists in the catalogue but data.svc never returns it: it is raised only on alias-mounted CRUD routes, and data.svc mounts none. Where it does apply it fires only when an authorizer is registered — with none registered the check fails open and the request proceeds. It is not a substitute for access rules, which deny by default.

Entity-level and row-level denials never carry these codes — they arrive as the CRUD code with a 403 status. See row-level security and field protection.

CodeStatusMeaningLikely cause
v2.export_render_failed500An export failed to renderA schema construct the exporter cannot represent, or a template failure
v2.cache_clear_failed500Clearing the caller’s tenant schema cache failedCache backend unavailable
v2.invalidate_failed500Superadmin cache invalidation for a target tenant failedCache backend unavailable, or the tenant does not resolve
v2.list_tenants_failed500The superadmin tenant listing failedConfiguration client unavailable

See schema export and caching.

CodeStatusMeaningLikely cause
v2.engine_unavailable500The per-tenant engine bundle could not be resolvedTenant configuration not loaded yet, definitions failed to compile, no datastore declared, or the database is unreachable
v2.engine_unexpected_type500The resolved engine does not implement the interface this surface needsDeployment wiring bug

v2.engine_unavailable is the most common boot-order failure. The wrapped message names the failing step. See schema sources and datastores.

GraphQL does not use the JSON error envelope. Field-level failures return 200 with the error in the errors array and the field set to null — including access denials, validation failures and constraint violations. Two transport-level rejections are plain text, not JSON:

ConditionStatusBody
Any verb other than POST405method not allowed
Unparseable request body400invalid JSON body

v2.no_tenant (403) and v2.engine_unavailable (500) are still returned in the JSON envelope, because they are raised before the handler resolves. Introspection is not served: __schema and __type validate but have no resolver, so they come back as cannot resolve field. See GraphQL.

The worksheet surface has its own catalogue and its own envelope. Statuses come from a fixed table, not from message classification.

CodeStatusMeaning
worksheet.not_found404No worksheet with that id, or it has been evicted
worksheet.expired410The TTL passed; the worksheet is inside the grace window
worksheet.cpet_violation403The worksheet belongs to a different tenant
worksheet.invalid_ttl400Requested TTL is outside the allowed range
worksheet.memory_exceeded507The worksheet exceeded its memory budget
file.not_found404No staged file with that id
file.uri_unreachable502A file referenced by URI could not be fetched
file.uri_access_denied403The remote store refused the fetch
file.format_invalid400Format unrecognised or unparseable; also when the multipart form has no file part
file.size_exceeded413Over the file-size, file-count, row or column limit
file.encoding_error400The character encoding could not be decoded
file.sheet_selection_required400A multi-sheet workbook needs an explicit sheet
table.name_conflict409A table with that name already exists
table.not_found404No such table in the worksheet
table.union_incompatible400Column sets or types do not line up
column.not_found404No such column on the table
query.syntax_error400The SQL failed to parse
query.timeout504The query exceeded its time budget
query.execution_error400The query parsed but failed at execution
invalid_request400Invalid JSON body on a worksheet call
rate_limit_exceeded429Worksheet rate limit; sends Retry-After: 60

Limits and the values behind each code are on worksheet limits.

Every handler under /data/admin/data/* and /data/superadmin/* returns {"error":"<message>"} with no code and no details. Only the auth gates in front of them use the coded envelope, so v2.requires_admin, v2.requires_superadmin, v2.missing_tenant and v2.invalid_tenant do appear on these routes — but nothing the handler itself raises does.

StatusMessage shapes
400plan_id query parameter required, plan id missing in path, missing :resource segment, claimer_id is required, confirmations: empty, entity path segment missing, invalid confirm_max_risk %q (use low / medium / high), body parse failures
401Always missing tenant identity
403tenant key missing from request context
404plan %q not found, entity <name> not found in schema
500Wrapped operational errors; engine resolution failures are prefixed engine_unavailable: inside the message string, not carried as a code

Plan apply is the exception to the table: it answers 207 whenever the result is anything other than fully applied, and carries a partial result object rather than an error body — {plan_id, status, steps_applied, steps_failed, steps_skipped, failed_step?, halted_step?, error?}. It falls back to 500 with the plain {"error":"<message>"} shape only when the apply produced no result at all. See migrations.

Three families of identifier look like error codes and are not.

Per-rule validation codes. REQUIRED, READONLY, FINAL, WRITE_ONCE, MIN, MAX, MIN_LENGTH, MAX_LENGTH, LENGTH, PATTERN, the format-checker codes (EMAIL, URL, URL_PROTOCOL, UUID, ULID, CUID, NANOID, SEMVER, PHONE, IP, HOSTNAME, MACADDRESS, PORT, JSON, DATAURI, CREDITCARD, LATITUDE, LONGITUDE, MIMETYPE, FILESIZE_MIN, FILESIZE_MAX, CONTAINS, NOTCONTAINS, STARTSWITH, ENDSWITH, NOTIN, DIVISIBLEBY, BEFORE, AFTER, PAST, FUTURE, PATTERN_UNKNOWN, VALIDATION_UNKNOWN), and the defaults ENTITY_VALIDATE, ENTITY_VALIDATE_ERR, BUSINESS_CONSTRAINT, BUSINESS_CONSTRAINT_ERR, POINTCUT_ERR, POINTCUT_ABORT are set on the internal validation error and never serialised. The response carries the CRUD code and the rule’s message only.

Schema-compile codes. ENTITY_NOT_FOUND, FIELD_NOT_FOUND, TYPE_MISMATCH, INVALID_ENUM_VALUE, RELATION_NOT_FOUND, FIELD_NOT_QUERYABLE, UNSUPPORTED_OPERATION, DUPLICATE_ENTITY, DUPLICATE_FIELD, SHADOW_PRODUCT_FIELD and INVALID_TRANSITION are declared constants with no emitter — nothing in the tree raises one. The schema front-end the deployable service uses reports load failures as plain wrapped errors naming the failing step, not as coded ones. A schema that fails to load never serves traffic, so a client sees nothing from this family either way. Do not branch on these names.

The legacy data-* catalogue. A large set of codes spelled data-<something> exists in the tree and is dead: no handler emits any of them. Do not build client branching on that list.