OriginChain docs
examples · errors

Error responses — copy-paste JSON.

← All examples

Every error from the OriginChain API is a JSON object with error, message, and status fields. Some carry extra typed fields — the addon code on a 402, the Retry-After header on a 429, the current row version on an OCC 409. Each example below is the request that triggers the error and the canonical body.

400 — bad request

400

400 — malformed JSON

The request body did not parse as JSON. The error body always carries a code, message, and HTTP status.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1",}'
Response
{
  "error": "invalid_json",
  "message": "trailing comma at byte offset 18",
  "status": 400
}
400

400 — unknown table

The SQL referenced a table that does not exist in the schema catalog.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT * FROM does_not_exist"}'
Response
{
  "error": "unknown_table",
  "message": "table 'does_not_exist' is not declared in any schema for tenant",
  "status": 400
}
400

400 — unknown column

The translator could not resolve a column reference against the table's manifest.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT bogus_col FROM shop.customers LIMIT 1"}'
Response
{
  "error": "unknown_column",
  "message": "column 'bogus_col' is not declared on table 'shop.customers'",
  "status": 400
}
400

400 — type mismatch

A literal in the WHERE clause did not match the column's declared type.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT id FROM shop.orders WHERE amount = '\''not-a-number'\''"}'
Response
{
  "error": "type_mismatch",
  "message": "column 'amount' is float64; literal 'not-a-number' is not a number",
  "status": 400
}
400

400 — unknown vector mode

Only fast and high_recall are valid topk modes.

Request
curl -X POST "$ENGINE/v1/tenants/$T/vector/products/topk" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": [0.1, 0.2, 0.3], "k": 5, "mode": "warp_speed"}'
Response
{
  "error": "invalid_argument",
  "message": "mode 'warp_speed' is not supported; valid values are 'fast' and 'high_recall'",
  "status": 400
}

401 — unauthenticated

401

401 — missing bearer

No Authorization header was sent.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
{
  "error": "unauthorized",
  "message": "missing Authorization header",
  "status": 401
}
401

401 — malformed bearer

The Authorization header was present but did not parse as a valid token.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: not-a-real-bearer" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
{
  "error": "unauthorized",
  "message": "Authorization header must be 'Bearer <token>'",
  "status": 401
}
401

401 — expired bearer

The token parsed but has expired or been revoked.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer eyJ...expired..." \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
{
  "error": "unauthorized",
  "message": "token expired at 2026-04-30T12:00:00Z",
  "status": 401
}

402 / 403 — billing & permission

402

402 — addon required

The endpoint is gated by an addon the tenant has not enabled. The body carries the addon code, name, monthly price, and a purchase URL.

Request
curl -X POST "$ENGINE/v1/tenants/$T/ask" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"question": "how many customers do I have?"}'
Response
{
  "error": "addon_required",
  "message": "natural-language SQL requires the 'ask' addon",
  "status": 402,
  "addon": "ask",
  "name":  "Natural language SQL",
  "monthly_usd": 99,
  "purchase_url": "https://originchain.ai/app/addons?enable=ask"
}
403

403 — forbidden (cross-tenant access)

The bearer is valid but does not have access to the requested tenant.

Request
curl -X POST "$ENGINE/v1/tenants/other-tenant/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
{
  "error": "forbidden",
  "message": "token does not authorise access to tenant 'other-tenant'",
  "status": 403
}

404 — not found

404

404 — instance not found

The engine endpoint host did not match any provisioned instance.

Request
curl -X POST "https://nope.ap-south-1.db.originchain.ai/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
{
  "error": "not_found",
  "message": "no instance is provisioned at this endpoint",
  "status": 404
}
404

404 — schema not found

The schema id in the URL is not registered for this tenant.

Request
curl "$ENGINE/v1/tenants/$T/schemas/does.not.exist" \
  -H "Authorization: Bearer $OC_TOKEN"
Response
{
  "error": "schema_not_found",
  "message": "no schema 'does.not.exist' for tenant",
  "status": 404
}

409 — conflict

409

409 — write-write conflict (snapshot isolation OCC)

Two concurrent CAS writes targeted the same row version. The losing write returns 409 with the latest version so the caller can retry.

Request
curl -X PUT "$ENGINE/v1/rows/shop.customers/c_42/cas" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d @- <<'JSON'
{
  "expected_version": 17,
  "row": { "id": "c_42", "email": "alice@example.com", "tier": "platinum" }
}
JSON
Response
{
  "error": "write_conflict",
  "message": "row 'c_42' is at version 18, expected 17",
  "status": 409,
  "current_version": 18
}
409

409 — addon already enabled

An addon-enable request hit a tenant where that addon is already on.

Request
curl -X POST "$ENGINE/v1/tenants/$T/addons" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"addon": "ask"}'
Response
{
  "error": "addon_already_enabled",
  "message": "addon 'ask' is already enabled for this tenant",
  "status": 409
}

413 / 422 / 429 — payload, semantic, rate-limit

413

413 — payload too large

The request body exceeded the per-call size limit. Split into smaller batches.

Request
curl -X POST "$ENGINE/v1/tenants/$T/rows/shop.products/_batch" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @huge-batch.json
Response
{
  "error": "payload_too_large",
  "message": "request body 64.2 MB exceeds limit of 32 MB",
  "status": 413,
  "limit_bytes": 33554432
}
422

422 — semantic error (too many JOIN tables)

SQL parsed successfully but exceeds a planner limit. The supported JOIN surface is up to five tables in a left-deep tree.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT a.id FROM a INNER JOIN b ON a.id=b.id INNER JOIN c ON b.id=c.id INNER JOIN d ON c.id=d.id INNER JOIN e ON d.id=e.id INNER JOIN f ON e.id=f.id"}'
Response
{
  "error": "unsupported_query",
  "message": "JOIN cardinality 6 exceeds limit 5",
  "status": 422
}
429

429 — rate limited (per-API-key quota)

The per-API-key quota has been exceeded. Honour the Retry-After header before retrying.

Request
curl -i -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
HTTP/1.1 429 Too Many Requests
Retry-After: 7
Content-Type: application/json

{
  "error": "rate_limited",
  "message": "API key has exceeded its per-second request quota",
  "status": 429,
  "retry_after_seconds": 7
}

5xx — server

500

500 — backend error

An unexpected server error. Trace id is included in the response and the headers; share it when contacting support and check the status page.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
{
  "error": "internal_error",
  "message": "unexpected backend error; please retry. If this persists, contact support with the trace id below.",
  "status": 500,
  "trace_id": "0b1c2d3e-4f50-6172-8390-a1b2c3d4e5f6",
  "status_page": "https://status.originchain.ai"
}
502

502 — engine unreachable

The control plane could not reach the tenant's engine. Usually transient; retry with backoff and check the status page if it persists.

Request
curl -X POST "$ENGINE/v1/tenants/$T/sql" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT 1"}'
Response
{
  "error": "engine_unreachable",
  "message": "control plane could not reach the engine for this tenant",
  "status": 502,
  "trace_id": "5f4e3d2c-1b0a-9988-7766-554433221100",
  "status_page": "https://status.originchain.ai"
}