Errors
Understand the error envelope, retry hints and the fields needed for safe diagnosis.
For authoritative HTTP errors, status-document and protocol exceptions, see public contracts. Inspect error.code and retry only where the operation permits it.
All public /v1 routes return a single, consistent error shape — the unified error envelope — with a stable, machine-readable code. Match on code, never on the human-readable message, which may change.
Base URL: https://api.qdivision.ai/v1
Error envelope
Every /v1 error response has this shape:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded",
"status": 429,
"correlation_id": "req_abc123",
"doc_url": "https://developers.getq.ai/errors#rate_limited",
"request_log_url": "https://developers.getq.ai/logs/req_abc123"
}
}| Field | Description |
|---|---|
code | Stable machine-readable identifier — see error reference below |
message | Human-readable explanation (may change; do not match on it) |
status | HTTP status code, mirrored from the response status line |
correlation_id | Request identifier for support and log correlation (also returned as the X-Request-Id header) |
doc_url | Link to this page, anchored to the error code |
request_log_url | Link to the request in the developer portal (present when correlation_id is set) |
Always include the correlation_id when contacting support so we can trace the request in our logs.
Streaming endpoints emit an inline
errorevent over SSE before closing the connection rather than returning an HTTP error body. Handle both HTTP-level errors and stream-levelerrorevents.
Error-code taxonomy
Summary table grouped by category. Each code has a dedicated section in the error reference.
Authentication and authorisation
| Code | Meaning | Status |
|---|---|---|
missing_or_invalid_auth | Authentication required (no valid credentials) | 401 |
invalid_token | Invalid authentication token | 401 |
token_expired | Authentication token has expired | 401 |
missing_api_key | API key is required | 401 |
invalid_api_key | Invalid API key | 401 |
api_key_expired | API key has expired | 401 |
auth_not_configured | Authentication is not configured | 401 |
insufficient_scopes | Key lacks a required scope | 403 |
Validation
| Code | Meaning | Status |
|---|---|---|
invalid_job_id | Invalid job identifier | 400 |
invalid_uuid | Invalid identifier format | 400 |
missing_tenant_id | Tenant identifier is required | 400 |
invalid_tenant_id | Invalid tenant identifier | 400 |
tenant_mismatch | Tenant identifier does not match the resource | 403 |
missing_required_field | A required field is missing | 400 |
invalid_request_body | Invalid request body | 400 |
validation_error | Request validation failed | 422 |
embedding_model_not_allowed | Embedding model is not allowed | 400 |
Resources
| Code | Meaning | Status |
|---|---|---|
job_not_found | Job not found | 404 |
document_not_found | Document not found | 404 |
resource_not_found | Resource not found | 404 |
State and conflicts
| Code | Meaning | Status |
|---|---|---|
job_not_completed | Job has not completed | 400 |
job_already_exists | Job already exists | 409 |
job_failed | Job failed | 400 |
invalid_job_state | Job is in an invalid state for this operation | 400 |
content_not_available | Content is not available | 400 |
Rate limiting
| Code | Meaning | Status |
|---|---|---|
rate_limited | Rate limit exceeded — see Retry-After and X-RateLimit-* headers | 429 |
Billing and entitlements
| Code | Meaning | Status |
|---|---|---|
budget_exceeded | Usage budget exceeded | 402 |
feature_unavailable | Feature is not available on your plan | 403 |
forbidden | Access denied | 403 |
Timeouts
| Code | Meaning | Status |
|---|---|---|
request_timeout | Request timed out | 408 |
stream_timeout | Stream timed out | 504 |
Service
| Code | Meaning | Status |
|---|---|---|
internal_error | Internal server error | 500 |
database_error | Database service unavailable | 503 |
task_queue_error | Task queue service unavailable | 503 |
llm_error | Language model service unavailable | 503 |
storage_error | Storage service unavailable | 503 |
service_unavailable | Service temporarily unavailable | 503 |
Error reference
Detailed documentation for every stable error code.
Authentication and authorisation
missing_or_invalid_auth {#missing_or_invalid_auth}
HTTP 401 — No valid credentials were provided, or the credentials could not be parsed.
Typical causes: Missing Authorization header, malformed Bearer token, empty API key.
Resolution: Send Authorization: Bearer q_… or X-API-Key: q_…. See Authentication.
invalid_token {#invalid_token}
HTTP 401 — The authentication token is not recognised.
Typical causes: Wrong JWT, corrupted token, token from a different environment.
Resolution: Obtain a fresh token or use an API key for /v1 integrations.
token_expired {#token_expired}
HTTP 401 — The authentication token has expired.
Resolution: Refresh the token or re-authenticate.
missing_api_key {#missing_api_key}
HTTP 401 — An API key is required but was not supplied.
Resolution: Set Q_API_KEY or pass the key in the Authorization header.
invalid_api_key {#invalid_api_key}
HTTP 401 — The API key is not valid or has been revoked.
Resolution: Create a new key in the developer portal.
api_key_expired {#api_key_expired}
HTTP 401 — The API key has passed its expiration date.
Resolution: Rotate to a new key with a future expiration.
auth_not_configured {#auth_not_configured}
HTTP 401 — Authentication is not configured on this deployment.
Resolution: Contact your Q administrator — this is an environment configuration issue.
insufficient_scopes {#insufficient_scopes}
HTTP 403 — The API key lacks a required scope for this endpoint.
Typical causes: Calling Sonar without ai:chat, Answer Engine without ai:answer, or embeddings without ai:embeddings.
Resolution: Add the required scope when creating or rotating the key. Use ai:* for full AI access. See Authentication — Scopes.
Validation
invalid_job_id {#invalid_job_id}
HTTP 400 — The job identifier is not valid.
Resolution: Pass a valid UUID for the job id path or query parameter.
invalid_uuid {#invalid_uuid}
HTTP 400 — A path or body field expected a UUID but received an invalid value.
Resolution: Ensure identifiers match UUID format (550e8400-e29b-41d4-a716-446655440000).
missing_tenant_id {#missing_tenant_id}
HTTP 400 — A tenant identifier is required for this operation.
Resolution: Ensure your API key is tied to an organisation, or pass tenant_id explicitly where supported.
invalid_tenant_id {#invalid_tenant_id}
HTTP 400 — The tenant identifier format is invalid.
Resolution: Use the organisation CUID from Route Royal / the developer portal.
tenant_mismatch {#tenant_mismatch}
HTTP 403 — The tenant in the request does not match the authenticated key's organisation.
Resolution: Remove conflicting tenant_id overrides or use a key for the correct organisation.
missing_required_field {#missing_required_field}
HTTP 400 — A required JSON field is absent.
Resolution: Check the OpenAPI spec or reference for required fields on this endpoint.
invalid_request_body {#invalid_request_body}
HTTP 400 — The request body could not be parsed or is structurally invalid.
Resolution: Send valid JSON with the correct Content-Type: application/json.
validation_error {#validation_error}
HTTP 422 — Request validation failed (Pydantic / schema constraints).
Resolution: Review field types, enums, and constraints in /v1/openapi.public.json.
embedding_model_not_allowed {#embedding_model_not_allowed}
HTTP 400 — The requested embedding model is not enabled for your tenant.
Resolution: Use an allowed model from GET /v1/embeddings config or contact support to enable the model.
Resources
job_not_found {#job_not_found}
HTTP 404 — No job exists with the given identifier.
Resolution: Verify the job id and that it belongs to your tenant.
document_not_found {#document_not_found}
HTTP 404 — The requested document does not exist.
Resolution: Confirm the document id and ingestion status.
resource_not_found {#resource_not_found}
HTTP 404 — The requested resource does not exist.
Resolution: Verify the resource id, path, and tenant scope.
State and conflicts
job_not_completed {#job_not_completed}
HTTP 400 — The operation requires a completed job, but the job is still running or pending.
Resolution: Poll the job status endpoint or subscribe to webhooks for completion events.
job_already_exists {#job_already_exists}
HTTP 409 — A job with this identifier already exists.
Resolution: Use a new idempotency key or fetch the existing job result.
job_failed {#job_failed}
HTTP 400 — The job completed with a failure status.
Resolution: Inspect job error details and retry with corrected inputs.
invalid_job_state {#invalid_job_state}
HTTP 400 — The job is in a state that does not allow this operation.
Resolution: Wait for the appropriate state transition or create a new job.
content_not_available {#content_not_available}
HTTP 400 — Requested content is not yet available (e.g. still processing).
Resolution: Retry after the job completes or content is indexed.
Rate limiting
rate_limited {#rate_limited}
HTTP 429 — Rate limit exceeded for your API key tier.
Resolution: Respect the Retry-After header and implement exponential backoff. See Status & SLA — Rate limit tiers.
Billing and entitlements
budget_exceeded {#budget_exceeded}
HTTP 402 — Your organisation's usage budget has been exceeded.
Resolution: Upgrade your plan or increase budget limits in the developer portal.
feature_unavailable {#feature_unavailable}
HTTP 403 — This feature is not included in your current plan.
Resolution: Upgrade entitlements or contact sales.
forbidden {#forbidden}
HTTP 403 — Access to this resource or action is denied.
Resolution: Verify scopes, tenant access, and feature entitlements.
Timeouts
request_timeout {#request_timeout}
HTTP 408 — The request exceeded the server-side timeout.
Resolution: Retry with a smaller payload, use async endpoints, or increase client timeout for long operations.
stream_timeout {#stream_timeout}
HTTP 504 — An SSE or streaming response timed out.
Resolution: Reconnect using Last-Event-ID where supported, or switch to async + webhook delivery.
Service
internal_error {#internal_error}
HTTP 500 — An unexpected server error occurred.
Resolution: Retry with backoff. Include correlation_id when contacting support.
database_error {#database_error}
HTTP 503 — The database service is unavailable.
Resolution: Check platform status and retry.
task_queue_error {#task_queue_error}
HTTP 503 — The background task queue is unavailable.
Resolution: Retry later; async job submission may be temporarily degraded.
llm_error {#llm_error}
HTTP 503 — The language model provider is unavailable or returned an error.
Resolution: Retry with backoff or switch models. Check /v1/status for llm_providers health.
storage_error {#storage_error}
HTTP 503 — Object storage is unavailable.
Resolution: Retry artifact or document operations later.
service_unavailable {#service_unavailable}
HTTP 503 — The service is temporarily unavailable.
Resolution: Check /v1/status and retry with exponential backoff.
Handling errors in code
Both SDKs parse the envelope into typed exceptions and surface code, correlation_id, doc_url, and request_log_url.
from q_client.exceptions import QRateLimitError, QAuthError
try:
await q.sonar.chat(model="sonar", messages=[...])
except QRateLimitError as e:
code = e.body["error"]["code"] # "rate_limited"
correlation_id = e.body["error"]["correlation_id"]
doc_url = e.body["error"]["doc_url"]
# Back off and retry using the Retry-After header
except QAuthError:
# Check Q_API_KEY (see Authentication)
...import { QRateLimitError, QAuthError } from "@getq/sdk";
try {
await q.sonar.chat({ model: "sonar", messages: [...] });
} catch (e) {
if (e instanceof QRateLimitError) {
const code = (e.body as any)?.error?.code; // "rate_limited"
const docUrl = (e.body as any)?.error?.doc_url;
}
if (e instanceof QAuthError) {
// check API key
}
}Related
- Authentication — auth error codes in context
- Webhooks — async completion instead of polling
- Idempotency — safely retrying after
5xxand timeout errors - Status & SLA — checking platform health