Error codes reference

Every query and HTTP error in Relata carries a structured RFC 7807 application/problem+json response. This page enumerates the error variants, their causes, and the suggested fix.

Deep-linkable errors. Every error response carries a type URI of the form https://relatadb.dev/errors/<code>, and each code resolves to a dedicated page with the cause and remediation. Look up any code (in any form the server emits) at relatadb.dev/errors — or click the code column below.

RFC 7807 response shape

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
 
{
  "type": "https://relatadb.dev/errors/parse",
  "title": "Bad Request",
  "status": 400,
  "detail": "unexpected token 'SELEC' after query end",
  "instance": "/query",
  "correlation_id": "0192a4f8-7e1c-7c3a-9b02-2c4d5e6f7a8b"
}
FieldMeaning
typeURI identifying the error class — stable across releases
titleHTTP status phrase (per RFC 9110)
statusHTTP status code
detailHuman-readable cause (English; may change between releases)
instanceThe route that produced the error
correlation_idUUIDv7 — cite this in ops tickets

HTTP status semantics

StatusMeaningRetry?
400Bad Request — client-side problem (parse error, bad argument)No — fix the request
401Unauthorized — missing or invalid bearer tokenNo — supply a token
403Forbidden — ACL denied access (the principal lacks a permission)No — request access
404Not Found — the type, route, or backup artefact does not existNo
405Method Not Allowed — wrong HTTP verb on a known routeNo
409Conflict — write lease held by another node; or row already existsYes, after lease TTL
413Payload Too Large — exceeded DefaultBodyLimitNo — chunk the request
422Unprocessable Entity — semantically invalid (e.g. backup SHA mismatch)No
429Too Many Requests — admission control or rate limit hitYes, after Retry-After — see Rate-limit headers
500Internal Server Error — server-side bug or storage failureMaybe, with backoff
501Not Implemented — recognised but unimplemented featureNo
503Service Unavailable — server is draining or shutting downYes, after restart

QueryError variants (canonical list)

These are the variants of the query error type that surface as RFC 7807 errors.

VariantcodeHTTPCauseSuggested fix
MissingPurposeREL_PURPOSE403Query lacks PURPOSE (only raised in strict mode — RELATA_PURPOSE_MODE=strict)Prefix the query with PURPOSE '<id>' or relax the mode
TimeoutREL_TIMEOUT408 / 504Execution exceeded RELATA_QUERY_TIMEOUT_SECSAdd LIMIT, add an index, or raise the timeout
WatchLimitREL_WATCH_LIMIT429RELATA_MAX_WATCH_SUBSCRIPTIONS reachedClose unused subscriptions or raise the cap
UnknownPurposeREL_PURPOSE_UNKNOWN403Purpose not registered in PurposeRegistryRegister it via the config, or use a known purpose
ParseErrorREL_PARSE400SQL / Cypher / GQL syntax errorFix the syntax (v1.5.0 adds line:column)
UnknownTypeREL_UNKNOWN_TYPE404Object type not registeredPOST /types to register it
UnknownColumnREL_UNKNOWN_COLUMN400Column not in the type's declared contractCheck the type definition or remove the column
AccessDeniedREL_ACL403ACL denied the principal accessGrant the permission via the policy table
StorageREL_STORAGE500Storage error (disk full, manifest corruption, etc.)Check /debug/stats; contact ops
HumintProtectedTypeREL_HUMINT403Tried to read a HUMINT-protected type without break-glassUse the break-glass unmask flow
MissingAccessScopeREL_ACCESS_SCOPE403Type requires access_scope_refPass the scope reference
CrossOrganizationAccessDeniedREL_XORG403No SharingAgreement covers this cross-org accessEstablish a sharing agreement
QuotaExceededREL_QUOTA429Tenant admission quota exceededWait, or raise the tenant quota
ResultCapExceededREL_RESULT_CAP406Result exceeded RELATA_MAX_RESULT_ROWSAdd LIMIT, or raise the cap (carefully)
VectorBudgetExceededREL_VECTOR_BUDGET406Vector k exceeds RELATA_MAX_VECTOR_KLower the LIMIT, or raise/disable the budget via RELATA_MAX_VECTOR_K
MaskedColumnInAggregateREL_MASKED_COLUMN400ACL-masked column used as aggregate/sort/group targetRemove the masked column from aggregates
QueueFullREL_QUEUE_FULL429All query priority queues are at capacityRetry with backoff
ProtectedTypeColumnREL_PROTECTED_COLUMN403Column name references a protected typeRemove the protected column from the query
InternalErrorREL_INTERNAL500Bug; the detail is masked in client_safe_msgFile an issue with the correlation_id

Rate-limit headers

All 429 responses from the per-IP token-bucket rate limiter include the following headers:

HeaderValueDescription
Retry-Afterseconds (integer)Minimum seconds before retrying — always 1 for the normal rate-limit bucket
X-RateLimit-LimitintegerRequests-per-second quota that applies to this endpoint
X-RateLimit-RemainingintegerTokens remaining in the current window — always 0 on a 429
X-RateLimit-ResetUnix epoch secondsWhen the next token becomes available

Example 429 response:

HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 1
X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1753128001
 
{
  "type": "https://relatadb.dev/errors/REL_RATE_LIMITED",
  "title": "Too Many Requests",
  "status": 429,
  "detail": "Per-IP rate limit exceeded for /query.",
  "instance": "/query",
  "retryable": true
}

SDK clients should inspect Retry-After and back off before retrying. Quota values are controlled by RELATA_RATE_LIMIT_RPS, RELATA_READ_RATE_LIMIT_RPS, and RELATA_MEMORY_RATE_LIMIT_RPS (see Environment Variables).

SDK error mapping

Each SDK maps the RFC 7807 response to a typed exception:

Python

from relata.exceptions import (
    RelataParseError, RelataAccessDenied, RelataQuotaExceeded,
    RelataTimeout, RelataResultCapExceeded, RelataError,
)
 
try:
    client.query("SELEC * FROM Person")
except RelataParseError as e:
    print(e.detail)        # "unexpected token 'SELEC' after query end"
    print(e.correlation_id)  # "0192a4f8-..."
except RelataAccessDenied as e:
    print(f"missing permission: {e.detail}")
except RelataError as e:     # catch-all parent
    print(e.type_uri, e.status)

TypeScript

import {
  RelataParseError, RelataAccessDenied, RelataQuotaExceeded,
  RelataError,
} from "@zysec-ai/relata-sdk";
 
try {
  await relata.query({ sql: "SELEC * FROM Person" });
} catch (e) {
  if (e instanceof RelataParseError) {
    console.error(e.detail);          // string
    console.error(e.correlationId);   // UUIDv7
  } else if (e instanceof RelataError) {
    console.error(e.typeUri, e.status);
  }
}

Go

import "github.com/relatadb/RelataDB/sdks/go/relata"
 
var errRelata *relata.Error
if errors.As(err, &errRelata) {
    log.Printf(
        "type=%s status=%d detail=%s correlation=%s",
        errRelata.Type, errRelata.Status, errRelata.Detail, errRelata.CorrelationID,
    )
}

Common error scenarios

"no PURPOSE declared"

You're in strict mode (RELATA_PURPOSE_MODE=strict). Either prefix your query with PURPOSE '<id>' or set RELATA_PURPOSE_MODE=open for dev.

"access denied: principal 'X' cannot perform 'read' on 'Person'"

The principal's ACL role lacks read on Person. Add a policy:

PURPOSE 'admin' INSERT INTO Policy (principal, permission, object_type)
VALUES ('alice@example.com', 'read', 'Person')

"WATCH rejected: subscription limit reached"

Each WATCH subscription re-evaluates on every commit, so the cap (RELATA_MAX_WATCH_SUBSCRIPTIONS) protects commit latency. Close unused subscriptions, or raise the cap on a write-light workload.

"ResultCapExceeded"

Your query result is larger than RELATA_MAX_RESULT_ROWS (default 1,000,000). Add LIMIT N, narrow the WHERE, or — for legitimate bulk exports — use GET /export instead of /query.

"VectorBudgetExceeded"

Vector search clamps the requested k to RELATA_MAX_VECTOR_K (default 1000). Lower the requested LIMIT, or raise/disable the cap via RELATA_MAX_VECTOR_K=0.

Reporting errors

When filing an issue, always include:

  1. The correlation_id (UUIDv7) from the response.
  2. The type URI.
  3. The full detail string.
  4. The server version (/version).
  5. The route (instance field).
  6. The query or request body that triggered it.

Without the correlation_id, ops cannot trace the request through the logs.

See also