Skip to content

Reading errors

Errors come back as RFC 7807-style application/problem+json. type is a stable identifier URI, and each one resolves to a page at https://docs.d2b.dev/errors/<slug>.

{
"type": "https://docs.d2b.dev/errors/validation",
"title": "Transform validation failed",
"detail": "Avoid hard-coding source names in the template …",
"status": 400,
"trace_id": "8f3c…",
"suggested_fix": "Use {{ arg }} placeholders and bind via `args`. See /api/v1/workbooks/{cid}/artifacts to discover names.",
"alternative_tools": ["get_lineage"]
}

suggested_fix is written so an LLM can read it and decide its next action — the recommended pattern is to pass the whole exception message back into your agent’s loop. The SDKs raise exceptions carrying it; the CLI prints the same text to stderr.

typeTypical statusMeaning
validation400 / 422The input doesn’t meet the contract (failed SQL, name rules, hard-coded template references …)
propagation-failed400The transform was saved and materialised; a downstream transform then failed to rebuild
unauthorized401Missing, malformed or revoked PAT
forbidden403Missing scope, a policy (mask / deny) refusal, or outside a workbook-scoped PAT
unknown-workbook404The workbook doesn’t exist or isn’t visible
unknown-artifact404The table/artifact doesn’t exist, or its type isn’t exposed on /api/v1
conflict409Optimistic lock (expected_version drift), a busy workbook, or a duplicate name
rate-limited429Rate limit hit. Honour Retry-After
internal5xxA server-side failure. Report it with the trace_id

5xx responses use the same problem+json envelope. The trace_id (also in the X-D2B-Trace-Id response header) maps 1:1 to the server-side stack trace — include it when reporting. Failed async ingest jobs carry trace_id and the failing phase on the job record too.

For surfaces where REST vocabulary (GET /api/...) doesn’t fit, applicable errors also ship suggested_fix_cli (in d2b ... vocabulary). The CLI shows that variant automatically.