Spectron uses standard HTTP status codes and follows RFC 7807 Problem Details for all error responses.
Error response format
All errors return a JSON body with the following fields:
{
"type": "https://spectron.dev/errors/context-not-found",
"title": "Context not found",
"status": 404,
"detail": "No context with id 'acme-staging' exists on this server.",
"instance": "/api/v1/contexts/acme-staging"
}| Field | Description |
|---|---|
type | A URI identifying the error type. Stable across versions. |
title | A short, human-readable summary of the problem type. |
status | The HTTP status code. |
detail | A human-readable explanation specific to this occurrence. |
instance | The request path that produced the error. |
HTTP status codes
400 Bad Request
The request body or query parameters are invalid. Common causes:
Malformed JSON body
Missing required fields
Invalid field values (e.g. unknown
modefor knowledge query)Scope floor violation (requesting a scope narrower than the key's floor)
{
"type": "https://spectron.dev/errors/validation-error",
"title": "Validation error",
"status": 400,
"detail": "Field 'mode' must be one of: vector, bm25, hybrid, hybrid_graph. Got: 'fuzzy'.",
"instance": "/api/v1/acme-prod/query"
}401 Unauthorized
No Authorization: Bearer token was provided, or the key is malformed.
{
"type": "https://spectron.dev/errors/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "API key missing. Include 'Authorization: Bearer <key>' in your request.",
"instance": "/api/v1/acme-prod/sessions"
}403 Forbidden
The API key is valid but does not have permission to perform this operation. Common causes:
Agent key attempting a management operation
Key's scope floor does not include the requested scope
Agent key attempting to persist a reflection (requires supervisor principal)
{
"type": "https://spectron.dev/errors/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "This operation requires a management key. The provided key has principal 'agent'.",
"instance": "/api/v1/contexts"
}404 Not Found
The requested resource does not exist.
{
"type": "https://spectron.dev/errors/not-found",
"title": "Not found",
"status": 404,
"detail": "No document with id 'document:0197d8f2...' exists in context 'acme-prod'.",
"instance": "/api/v1/acme-prod/documents/0197d8f2"
}409 Conflict
A resource with the same identifier already exists, or an idempotency conflict occurred:
Duplicate Context id on create
Duplicate principal
display_nameon create (when no matchingexternal_idcreate-or-get applies)Same
Idempotency-Keywith a different request body on/factsor/facts/batchDuplicate idempotency request while the first is still in flight
{
"type": "https://spectron.dev/errors/conflict",
"title": "Conflict",
"status": 409,
"detail": "A context with id 'acme-prod' already exists.",
"instance": "/api/v1/contexts/acme-prod"
}413 Payload Too Large
The uploaded file exceeds the per-Context size limit.
{
"type": "https://spectron.dev/errors/payload-too-large",
"title": "Payload too large",
"status": 413,
"detail": "Uploaded file size (52.4 MB) exceeds the per-context limit (50 MB).",
"instance": "/api/v1/acme-prod/documents"
}422 Unprocessable Entity
The request is syntactically valid but semantically invalid.
{
"type": "https://spectron.dev/errors/unprocessable",
"title": "Unprocessable entity",
"status": 422,
"detail": "Cannot bind context to namespace 'spectron' – this namespace is reserved for internal use.",
"instance": "/api/v1/contexts/test"
}429 Too Many Requests
The Context is blocked from LLM-backed work, or a per-minute rate limit was hit.
Token budget: returns 429 when enforcement_blocked is true on the Context (org credit enforcement on Cloud, or an operator-set block). A soft token_limit breach alone does not reject while enforcement_blocked is false — usage continues under pay-as-you-go.
Applies to LLM-backed paths including /chat, /facts?infer=full, /reflect, and /consolidate — not to read-only cache hits or direct lookups.
{
"type": "https://spectron.dev/errors/rate-limited",
"title": "Too many requests",
"status": 429,
"detail": "Token enforcement is blocked for context 'acme-prod'.",
"instance": "/api/v1/acme-prod/sessions/sess_abc/turns",
"retry_after": null
}500 Internal Server Error
An unexpected error occurred server-side. The detail field contains a request ID for support escalation.
{
"type": "https://spectron.dev/errors/internal",
"title": "Internal server error",
"status": 500,
"detail": "An unexpected error occurred. Request ID: req_01HF3X...",
"instance": "/api/v1/acme-prod/context"
}503 Service Unavailable
The server is temporarily unable to handle requests – typically during a SurrealDB connection issue or startup.
SDK exceptions
Python SDK
| Exception | HTTP status | When |
|---|---|---|
SpectronAuthError | 401 | Missing or invalid API key |
SpectronScopeError | 403 | Scope floor or principal rejects the call |
SpectronNotFoundError | 404 | Resource does not exist |
SpectronAPIError | Other non-2xx | Generic API failure (includes 400, 409, 429, 5xx) |
from surrealdb import SpectronNotFoundError, SpectronAPIError
try:
doc = await client.documents.get("document:nonexistent")
except SpectronNotFoundError as e:
print(f"Document not found: {e.message}")
except SpectronAPIError as e:
if e.status_code == 429:
print(f"Rate limit exceeded: {e.body}")See the SDK error sections for Python and JavaScript for the full hierarchy and retry behaviour.
JavaScript SDK
| Error class | HTTP status | When |
|---|---|---|
AuthError | 401 | Missing or invalid API key |
ScopeError | 403 | Scope floor or principal rejection |
NotFoundError | 404 | Resource does not exist |
ValidationError | 400, 422 | Invalid request payload |
RateLimitError | 429 | Token or rate limit exceeded |
ServerError | 500, 503 | Server-side failure |
ConnectionError | — | Network failure or timeout |
import { NotFoundError, RateLimitError } from "@surrealdb/spectron";
try {
const doc = await client.documents.get("document:nonexistent");
} catch (e) {
if (e instanceof NotFoundError) {
console.error("Document not found:", e.detail);
} else if (e instanceof RateLimitError) {
console.error("Rate limit exceeded");
}
}Ingestion pipeline errors
Documents that fail during async processing do not return HTTP errors – they set the document status to "failed" and populate the error field:
{
"id": "document:0197d8f2...",
"status": "failed",
"error": "PDF extraction failed: file is encrypted and no password was provided.",
"processing_started_at": "2026-05-12T14:22:11Z",
"processing_completed_at": "2026-05-12T14:22:14Z"
}Poll GET /api/v1/{context_id}/documents/{id} to check document status. See Uploading documents for retry guidance.
MCP error handling
MCP tool failures use a different envelope from REST, but carry the same HTTP status semantics:
Operation failures →
isError: truetool result withstructuredContent.error.status(404, 403, 429, etc.). The JSON-RPC transport returns HTTP 200.Protocol faults → JSON-RPC
error(bad params, unknown tool).
Auth failures and missing Contexts are masked as 401, never 404, so unauthenticated callers cannot enumerate Context ids. See MCP tools.