Skip to main content

Errors

Every error the API returns has one envelope and a code from a closed set. The reasons inside a field_states entry are a different list (field states).

The error envelope​

Every error uses OpenAI's envelope, with one field added, retry:

{"error": {"type": "invalid_request_error", "code": "not_maintained",
"message": "fx:USDEUR is not maintained; the maintained pair is fx:EURUSD (USDEUR = 1 / EURUSD)",
"param": "pair", "retry": "never"}}
fieldmeaning
typeinvalid_request_error for a 4xx, server_error for a 5xx
codethe cause, from the closed set below; branch on it, never on message
messagea human-readable explanation; its wording can change
paramthe parameter at fault, when there is one; otherwise null
retrylater: the same request may succeed later; never: the answer is settled, do not retry; change_request: a different request can succeed, and the message names it

The tables below give retry per code. An error worth retrying soon also carries Retry-After (seconds, the earliest useful retry) and x-should-retry: true; every other error carries x-should-retry: false. A 503 temporarily_unavailable sends Retry-After: 300 unless its cause is known to last longer, when it sends that longer wait. A 503 service_unavailable or identity_provider_unavailable means a Tauric service is briefly down: it sends Retry-After: 10 or less. 429 quota_exhausted has no Retry-After; retry at its resets_at.

A few errors carry extra fields, named in their rows. A 409 ambiguous_instrument for a crypto asset spelling carries candidates (crypto).

The model-inference and copilot routes use the same envelope with their own OpenAI-style codes, listed on model inference and copilot.

Error codes​

A data code describes the data, so an immediate retry returns the same answer.

Data and coverage​

codeHTTP statusmeaningretry
not_registered404a well-formed spelling that is not registered; for an external or retired spelling, the message names the key to use; otherwise search GET /v1/instruments?q=… (find an instrument)change_request
not_maintained404registered, but this data is not maintained for it; a listing that left coverage carries maintenance (state: departed, coverage_end), and its history stays readable (listing lifecycle)never
delisted404a current read (quote, batch quote, technicals, analyst consensus, earnings calendar, research) of a delisted listing; its history is served through its last session, and the message names the effective date, the reason, and the SEC forms. Also returned when another listing now holds the symbol (listing lifecycle)never
not_supported404outside what the API serves, for example a security with no SEC filings served, or a route of the wrong shape for a series; the message names the right onenever
not_published404nothing is published for it (for example, a crypto pair with no trade in 24 hours)never
temporarily_unavailable503no current value can be served right now; the message says why and Retry-After when to retrylater
insufficient_history404the stored history does not reach as far back as askedchange_request
ambiguous_instrument409a spelling names more than one instrument; the message names themchange_request

The request​

codeHTTP statusmeaningretry
invalid_request400 / 422the request is malformed: a bad value, an unknown or repeated query parameter, an unknown body field; param names itchange_request
not_found404no such path, id, or documentchange_request
no_report404the research run is yours and has no stored report: it did not complete, or you deleted the reportchange_request
method_not_allowed405the path exists, but not with this methodchange_request
request_too_large413the request body is too largechange_request
conflict409the request conflicts with the current state of the resourcechange_request
gone410the resource existed and is no longer availablenever
unsupported_media_type415the body's Content-Type or Content-Encoding is not acceptedchange_request
range_not_satisfiable416the Range is not one range starting below the sizechange_request
session_deleted410the session was deleted; its id stays reservednever
model_not_found400 / 404a model other than the served one; the message names the served idchange_request

Keys, access, and accounts​

codeHTTP statusmeaningretry
missing_api_key401no API key was sentchange_request
invalid_api_key401the key is unknown or malformedchange_request
api_key_inactive401the key was revokedchange_request
api_key_expired403the key has expiredchange_request
account_inactive401the account the key belongs to is suspendednever
access_not_granted403the account is not active, or its tier includes no website access (no data, ai, or sessions entitlement)change_request
entitlement_required403your tier, or this kind of credential, does not include what this operation needs; the error's entitlement names it: data, ai, mcp, or sessions (entitlements)change_request
forbidden403the key is not allowed this operationchange_request
principal_not_permitted403this credential cannot call this operation; use your own keychange_request
owner_session_required403managing keys and sessions (/v1/account/…) needs the owner's website session, not an API keychange_request
credential_limit_reached409the account already holds its maximum of live keys; revoke one firstchange_request
invalid_session401a website session is missing or invalidchange_request
invalid_exchange_token, invalid_identity_token, csrf_failed, connection_unknown, connection_revoked, connection_replayed, invalid_grant401 / 403The sign-in or app connection is no longer valid: sign in again, or reconnect the app.change_request
identity_provider_unavailable503website sign-in is briefly unavailable; retry after Retry-After seconds (API keys are unaffected)later

Limits and the server​

codeHTTP statusmeaningretry
concurrency_limit_reached429the account already has its limit of research runs, copilot runs, and model-inference requests in progress at once (limit and in_flight are given); retry after Retry-After seconds, when one finisheslater
rate_limit_exceeded429the per-minute rate limit is exceeded; wait for the reset header (rate limit)later
quota_exhausted429a daily credit pool is spent: pool names it (data or ai), with remaining credits and resets_at, the next midnight UTC; the other pool may still have creditslater
server_error500a fault on Tauric's side; report it (report an issue)later
service_unavailable503temporarily unavailable; retry after Retry-Afterlater

The MCP server​

The hosted MCP server passes the API's typed errors through with the same code, and adds these (use with AI assistants):

codereturned asmeaningretry
missing_required_argumenttool error resulta required argument is missing; param and missing name it, and no request was madechange_request
unknown_parametertool error resultan argument the tool does not declare (a typo, or known_at on a tool that takes none); param and unknown name it, and no request was made. REST refuses the same mistake as 422 invalid_requestchange_request
response_too_largetool error resultthe result is over the size limit; nothing is returned, never a truncated result. The request was made, so it is charged (response size limit)change_request
invalid_authorization401the Authorization header is not exactly one Bearer <key>change_request
invalid_token401the access token from an MCP sign-in is not valid or has expired; the app refreshes it, or you connect the app againchange_request

Rules for every request​

Every /v1 route answers 422 invalid_request, with param naming the parameter, for an undeclared query parameter, a parameter sent twice, or a value outside a parameter's schema. An unknown field in a POST body is 422 invalid_request on the data routes and 400 unsupported_parameter on the copilot and model-inference routes. A batch request answers each key with the code its own route would answer (batch quotes). An unknown path answers 404 not_found; the API reference lists every route.

Report an issue​

Send one report per issue through the contact form at https://tauric.ai/contact, with:

  1. Request: the method, full path and query, and body (never the key, a session cookie, or an Authorization header).
  2. Response: the status, the full body (or the error object), and the x-ratelimit-* and x-quota-* headers.
  3. Time: the UTC time of the call.
  4. Expected and actual: why it is wrong, such as a wrong number, an expected data field that is null with no field_states entry, a code that contradicts /v1/datasets, a 500, or two routes that disagree (give both).
  5. Repeatability: whether it happened once or always, and whether a retry changed it.

A typed not_supported or not_maintained error, or a not_held reason, is expected behavior unless /v1/datasets and GET /v1/instruments/{key} say the dataset is served for that instrument.