Skip to content

Error Codes & Troubleshooting

There are two families of errors here, and they behave differently.

Plan and quota responses come back from the HTTP request itself, before or instead of a run. They carry a JSON body with a code field, and each one has a specific action that clears it. These are the ones a new account meets first, so they come first below.

Run failures happen inside a run that was accepted and started. They arrive as an error event on the stream (or on the finished run) with an error_code, and they’re grouped into five recovery classes.

Plan and quota responses

When a request is refused for plan reasons, the response body is a JSON object with a code. Branch on code, never on the HTTP status alone429 is shared between the rate limiter (which returns a plain string) and the quota system (which returns one of these objects), and 402 is shared by several distinct situations.

CodeStatusWhat happenedWhat clears it
quota_exceeded (scope: "month")429You’ve used every question your plan includes this calendar month. The body carries limit, used, and resets_at.Wait for the counter to reset at 00:00 UTC on the 1st of next month, or upgrade — the new allowance applies immediately. On a Team plan the pool is shared across the workspace, so more seats also raise it.
quota_exceeded (scope: "day")429Pro and Team carry a per-person fair-use ceiling of 500 questions per day. The body carries resets_at.Wait for the ceiling to reset at midnight UTC. Your monthly allowance is untouched.
discovery_limit429You’ve used every AI schema analysis your plan includes this month. The body carries limit, used, and resets_at.Wait for the monthly reset, or upgrade. Re-running structure-only discovery, resuming a checkpointed analysis, and retrying one that reuses existing introspection are all free — only a fresh schema analysis counts.
connection_limit402Creating, duplicating, or activating a connection would exceed your plan’s active-connection limit. With reason: "over_limit", it means you already hold more active connections than your plan allows — typically after a downgrade — and questions are blocked until you’re back under it.Pause a connection you don’t need right now (Connections page, or POST /api/v1/connections/{id}/paused), or upgrade. Pausing keeps the connection’s schema analysis and history.
connection_paused402The connection this request targets is paused. Paused connections can’t run questions or schema discovery.Activate it from the Connections page — which needs room under your connection limit — or target a different connection.
seats_full409An invite would exceed the seats on the Team subscription, or the workspace filled up between the invite being sent and accepted. The body carries seats and members.Add seats in the Stripe customer portal, or remove a member or a pending invite, then re-send.
team_min_seats422A Team checkout was requested with fewer than 2 seats.Check out with at least 2 seats, or pick Lite or Pro for a single user.
plan_blocked402An action that requires an active Team subscription was attempted without one — inviting teammates is the case you’ll actually meet.Start or restore a Team subscription. Note this code never means your account is suspended: an expired trial or a cancelled subscription lands you on the Free plan with your data intact, not in a blocked state.

Two things worth knowing about quota counting:

  • Counters increment when a request is accepted, so a run that then fails still consumes a question.
  • If the counter store is briefly unavailable, requests are allowed through rather than refused.

Plan limits themselves — how many questions, connections, and AI schema analyses each plan includes — are in Billing & plans.

Run failures

Once a run has started, failures are classified into five classes for recovery UX:

  • NO_RESULTS — the question was understood but produced no useful data.
  • TIMEOUT — execution exceeded its time limit.
  • PLAN_FAILURE — the model could not produce a valid plan.
  • CONNECTION_FAILURE — the database could not be reached.
  • INTERNAL — generated SQL/code was invalid, the sandbox crashed, or the model returned malformed output.

Every error event in the run stream carries an error_code that maps to one class.

NO_RESULTS

CodeMeaningRecovery
MISSING_TABLEGenerated SQL references a table not in scopeAdd the missing table to scope and retry.
MISSING_COLUMNGenerated SQL references a column that doesn’t existCheck your table selection or rephrase.
TYPE_MISMATCHImplicit cast failedRephrase to avoid mixing incompatible types.

The frontend surfaces these as “broaden your question” suggestions.

TIMEOUT

CodeMeaningRecovery
SQL_TIMEOUTDatabase query exceeded the query time limit (30 seconds)Add date filters or narrow scope.
SANDBOX_TIMEOUTSandbox Python step exceeded its wall-clock cap (90 seconds)Simpler analysis, or reduce the data volume it works on.

PLAN_FAILURE

CodeMeaningRecovery
NOT_ANSWERABLEThe model determined the question can’t be resolved with the data in scopeRephrase, or bring the missing tables into scope.
AMBIGUOUS_QUERYMultiple valid interpretationsBe more specific.

The frontend offers an editable retry — your question stays in the input ready to revise.

CONNECTION_FAILURE

CodeMeaningRecovery
CONNECTION_ERRORDatabase unreachableTest from sidebar; check credentials.

The frontend’s recovery banner has a “test connection” button.

INTERNAL

CodeMeaning
SQL_SYNTAXGenerated SQL didn’t parse
SQL_VALIDATIONGenerated SQL failed our validation rules
SQL_EXECUTIONDatabase returned an error
SANDBOX_CODE_ERRORPython in the sandbox raised
SANDBOX_OOMPython in the sandbox exceeded memory cap
LLM_INVALID_OUTPUTThe model returned a plan that didn’t match the required structure

Most of these trigger an automatic revise-and-retry, within strict limits. Once that budget is exhausted you see the underlying error.

  • Billing & plans — what each plan includes and how pausing a connection frees a slot.
  • REST API reference — the endpoints these responses come from.
  • Security — why some questions are refused before they run.