Skip to content

Reference — errors & gotchas

Cause → fix for the failures and misconceptions you will actually hit.

Contents

  • HTTP errors
  • SQL / join gotchas
  • Data-shape gotchas

HTTP errors

Symptom Cause Fix
describe_catalog(ws, experiment_id=…) → 404 experiment not published Tell the user to Publish results (or Run everything) in the UI; don't invent tables.
query_sql → 400 "no queryable data yet" workspace has no datasets/results Register a dataset or publish results first.
query_sql → 400 (statement rejected) non-SELECT, DDL/DML, or multiple statements Send exactly one read-only SELECT.
query_sql → 400 "table/column does not exist" used exp_<id>_* or guessed a name Use the data-kb tables[].name (RULE 1), double-quoted.
query_sql → 400 syntax error at or near "weeks" a DuckDB keyword written as a bare column alias (count(*) weeks) AS before every alias; quote a keyword alias wherever it appears (AS "weeks"). The error says so; overview.md, DuckDB idioms.
query_sql → 400 Function with name width_bucket does not exist another dialect's function The error names the DuckDB equivalent (floor(x / w) * w bins, histogram); the rest are in overview.md, DuckDB idioms.
any → 401 missing or revoked token when auth_required A person issues tokens (Settings → Access); set it as PARLEML_API_TOKEN — or reconnect the host's OAuth sign-in.
any → 401, reason token_expired the token's lifetime ran out (builder tokens last at most 90 days) Tell the person the token expired; they issue a new one (Settings → Access). A host signed in through OAuth refreshes or reconnects by itself.
any → 401, reason token_refused a token ParleML refuses: one minted under a scope name it does not know, or a builder token without an expiry Tell the person the token is refused; they issue a new one (Settings → Access) for the agent's configuration.
probe_dataset / what_if / simulate_decision / compare with kind="datasets" → "this token's scope lacks 'compute'" (or 403) token has the analyst scope Say which step needs the compute scope; a person grants it (Settings → Access — scopes gate tokens, not people). An analyst token is not offered the compute tools at all.
a builder tool → "this token's scope lacks 'builder'" (or 403) the token is not builder, or not bound to this workspace Say which step needs a builder token bound to the workspace; a person grants it — or does the step in the parleml UI. Promoting and deleting are never a token's.
a builder tool times out, or → 409 idempotency_key_in_use the call (or the first call with this key) is still running server-side In a session ParleML runs: wait once with the session tool await_operation (operation_id="call:", the message names it), then repeat the call with the same idempotency_key — it returns the stored result. Elsewhere: wait, then retry with the same key. Never with a new one, never in a sleep loop.
a builder tool → 409 idempotency_key_reused the key was used for a different request Omit idempotency_key for a new call; reuse a key only to retry the exact same call.
run_experiment(action="plan") → 400 naming mlflow an agent's experiment may not log to MLflow: logging registers the model and moves its aliases Drop the mlflow block; a release is a person's, in the parleml UI.
run_experiment(action="launch") → 409 the plan expired, its dataset or its column roles changed since planning, or it was already launched Plan again and review the new plan (the error says which); a launched plan's experiment is in get_workspace_brief.
run_experiment(action="launch") → 429 budget_exceeded the token's budget is spent; details.budget names it: max_estimate_band (the plan is too large), max_runs_per_day, max_concurrent_runs (with limit, used, window) Plan smaller; wait for the day's launches to renew; or let a run finish (list_resources("jobs")) — or ask the user to raise the budget. Don't retry in a loop.
register_model(action="import_predictions") → 413 the predictions file is over the upload limit Send fewer rows or columns.
query_sql → 400 (file path rejected) referenced a file/URL/glob as a table Only the registered view names are queryable — data-kb tables[].name.
capabilities → 404 type has no route (reco/ltr) or not computed Expected; the MCP get_capabilities returns a graceful note.
get_insight → available: false note that surface not computed / not applicable — or the kind reads the explanation profile and the Explain step has not run Expected shape, not an error; quote its reason when it says why. get_capabilities lists the kinds that wait for the Explain step. Suggest computing it in the UI when the user needs it.
get_insight → 422 naming a field a malformed param (e.g. top_k out of range) Fix the param the message names; this is not "not available".
get_chart_data("mli", "pdp") → 404 "No … curve was drawn" every column was skipped or its curve failed The message names each skipped column and why — quote it; don't call PDP "not computed".
get_eda → 404 EDA never computed for the dataset Open the dataset in the parleml UI first.

Tool-side errors (raised by the MCP, no backend call)

These carry the fix in the message — read it rather than retrying blind.

Symptom Cause Fix
"cannot reach the parleml backend at …" backend down, or wrong PARLEML_API_BASE A configuration problem — report it; retrying will not help.
a read or compute tool "… timed out after 30s" backend reachable but slow; nothing changed For SQL, narrow it. The signal probes keep computing and cache: the same call shortly returns the result.
a builder tool "… timed out …" the call may still be running Do not start it again: retry with the idempotency_key the message gives you.
"Unknown action …" / "… takes no params […]" / "… needs …" a builder tool's action, params or ids don't match The message lists what the action takes; the tool's description has the details.
"params.x must be true or false" / "a whole number" a flag sent as a string, a limit as text Send JSON booleans and numbers (true, not "true").
Unknown insight kind / Unknown chart kind invented a name The message lists the allow-list — pick from it; get_insight(id, "kinds") lists the kinds that apply to that experiment.
"Insight 'text_insight' requires params [...]" required query params missing get_capabilities(id).insight_encoders lists valid (encoder, feature) pairs.
"probe '…' requires params [...]" / "takes no params [...]" a probe param missing or misspelled The message lists the kind's params; their meaning is in api.md (Dataset probes).
"Help mode takes only family" get_chart_data without kind but with subject_id / params / render Pass kind to fetch a chart, or family alone to read the help.
"Invalid … id" id contains / # ? % or a space Ids come from list_resources / get_resource, never from free text in a result.

SQL / join gotchas

  • Joining an input by position → a silent mis-join: row_number() OVER () has no ORDER BY, so nothing promises it follows the file. Join on the declared key column(s) every per-row fact carries (RULE 3).
  • A per-row error or band coverage over every row → optimistic. The model trained on most of them; filter row_role = 'outer_test'.
  • Forecast joined on row_index → wrong. Forecast keys on (series, ts).
  • Unquoted identifiers → parse error on the __-heavy view names (and any that collide with SQL keywords). Always double-quote (RULE 4).

Data-shape gotchas

  • Multiclass proba_*: don't hardcode proba_1; read the actual proba_<class> columns from the catalog.
  • has_more=true: the result was silently truncated — aggregate or filter; never assume you got the full set.
  • Optional tables/columns absent (rules, archetypes, items, interval bounds, residual, distance, rank): guard with catalog presence (RULE 6).
  • ts is a string: cast (CAST(ts AS TIMESTAMP)) when range-filtering a forecast.
  • Anomaly scope=in_sample: scores cover only the fit set, not every row.