Skip to main content
Dataville uses standard HTTP status codes: 4xx for a problem with the request or account, 5xx for a problem on Dataville’s side or with an upstream source. Every error body includes a human-readable message that is safe to show to a user. Data-source failures also include a stable data.code for clients to branch on. Errors are never billed. Credit is deducted only after results are returned, and a download that fails part-way is refunded. Error responses do not count toward the anonymous request limit.

Error format

Data lookups (GET /{source}/{keywords}) return errors in the same envelope as results:
data.code is present on upstream and internal failures. Validation errors on these routes (an unsupported source, no results) use the same envelope without a code. Export, SQL, and connected-sheet routes return a flat shape:
Check the HTTP status first, then data.code or error where present.

Data source errors

These codes appear in data.code on data lookups. The UPSTREAM_* codes come from sources Dataville fetches live: Wikipedia, arXiv, Stack Exchange, PyPI, and OpenAlex. Sources served from Dataville’s own database fail as INTERNAL_ERROR or return a 404. UPSTREAM_RATE_LIMITED is the only error that sets a Retry-After header (in seconds, only when the source said how long to wait). Its message tells the caller it is not a limit on their account:

Validation errors (400)

The message states what to fix. On data lookups it is in data.error; elsewhere it is the flat shape. An unsupported source name returns the full list of valid names and aliases in the message. POST /api/v1/query accepts SELECT statements only. The validator rejects CREATE, DROP, ALTER, INSERT, UPDATE, DELETE, MERGE, TRUNCATE, COPY, ATTACH, DETACH, INSTALL, LOAD, EXPORT DATABASE, IMPORT DATABASE, read_csv, read_parquet, read_json, read_ndjson, GLOB, and postgres_scan with Disallowed operation: {OP}. Matching is textual, so these words are rejected inside string literals too. LIMIT is not validated. Queries are capped at 1,000 rows and the sql_executed field in the response shows the query that ran.

Authentication errors (401)

Routes that require a key return 401 when none is sent. Export and SQL routes use the flat shape:
Connected-sheet routes return:
An invalid or revoked key is handled the same way as no key: a 401 on these routes, and the anonymous allowance on data lookups. If keyed requests are hitting the anonymous rate limit, check account_state in the response. "anonymous" means the key was not accepted. See Create an API key.

Insufficient credit (402)

Returned when your credit balance can’t cover the request. Nothing is charged.
Upgrade or top off from the Billing page, or wait for the monthly reset. X-Credits-Remaining on successful responses shows the balance falling. See Usage limits.

Access errors (403 and 404)

These mean the thing you asked for doesn’t exist or isn’t yours.

Timeouts (408)

SQL queries and sheet searches are limited to 30 seconds:
Narrow the query: fewer columns, a WHERE clause, or a lower LIMIT. Nothing is billed.

Rate limit errors (429)

Three limits produce a 429, each with a different body. The limits themselves are on Usage limits. Anonymous request limit (50 per 24 hours per IP):
Export and SQL limit (1,000 per day per account):
The connected-sheet routes have a separate 1,000-per-day limit with an equivalent body. Both send RateLimit-* headers and Retry-After. Burst limit (100 per 15 minutes per IP) returns a plain-text body, not JSON: Too many requests from this IP, please try again after 15 minutes. Back off until Retry-After or the window resets, and send an API key. The anonymous limit is the one you will hit first.

Server errors (5xx)

Unexpected failures return 500 with { "error": { "message": "Internal Server Error" } }, or the INTERNAL_ERROR envelope on data lookups. 502 and 503 are upstream-source problems covered by the codes above. Retry with exponential backoff. If a 500 persists, email support@dataville.com with the request path and time.

Stale results are not errors

When arXiv is down and Dataville holds a stored copy of the result, the request succeeds with a 200 and a stale notice inside data:
cached_at is null when the copy’s age isn’t known. Stale responses are billed normally. If no stored copy matches, you receive the UPSTREAM_* error instead.

MCP errors

The MCP endpoint reports errors at two levels:
  • Tool errors are the common case. search_dataville returns a tool result with isError: true and a plain-text message mirroring the REST errors: unsupported source, with the valid names listed, no results, insufficient credit, or Search failed for {source}: {reason}. These arrive as HTTP 200.
  • HTTP errors come from the endpoint itself, which is stateless and POST-only. GET or DELETE /mcp returns 405. Rate limiting returns the same 429 bodies as the REST routes, not a JSON-RPC envelope.
The /mcp endpoint has no authentication error. With no key, or with an invalid one, the connection runs on the anonymous allowance and its limit of 50 requests per 24 hours.