detail object on every 4xx / 5xx, typically shaped:
detail as a plain string (notably 404s from lookup endpoints). In those cases there’s no reason_code; match on the status code and message.
For a working debugging flow using these codes, see Debug a failing decide.
By reason_code
missing_api_key — 401
/decide accepts ruleset_id on public rulesets; rulebook_id and all authoring endpoints do not. Add an x-api-key header.
invalid_api_key — 401
aethis login to mint a fresh one, or retrieve the correct key from your credential store.
api_key_expired — 401
denied_missing_permission — 403
missing_permissions is the authoritative list. For most authoring flows you’ll want decide, rulesets:read, rulesets:write, projects:write; composed rulebooks additionally need rulebooks:read / rulebooks:write. See REST API scopes.
reserved_namespace — 403
aethis/*). Pick a different namespace (e.g. my-team/*, my-company/*).
invalid_slug_format — 422
/-separated segments, starting with a letter. Common causes: uppercase letters, spaces, trailing /, leading -. See Nomenclature.
slug_conflict — 409
daily_quota_exceeded — 429
Retry-After: 86400 header. Upgrade your tier via support, wait for UTC midnight reset, or authenticate with a higher-tier key.
rate_limit_backend_unavailable — 503
decision_id from the most recent successful call for correlation.
Bare-string 404s (no reason_code)
Lookup endpoints return detail as a string rather than an object when the target doesn’t exist:
- Slug typo. Whitespace, capitalisation, or a
/mismatch. - Using
ruleset_idto look up a rulebook slug.aethis/uk-fsmis a rulebook slug; it won’t resolve from theruleset_idfield. Move the value torulebook_idand addx-api-key. See Nomenclature. - Ruleset is private. Anonymous
/decideonly returns public rulesets; private rulesets 404 from an unauthenticated caller to avoid leaking their existence. - Slug not yet resolved on this endpoint.
/explain-failuredoes not currently resolve slugs (only concrete ruleset_ids). Use theruleset_idreturned in your/decideenvelope instead.
Validation errors from FastAPI (422)
If you send a malformed request body — missing required field, wrong type, unknown enum value — FastAPI returns its own 422 shape:loc pinpoints the offending field. Common causes in authoring flows:
- Omitting
expected_outcomeonPOST /rulesets/{id}/explain-failure - Sending
outcome_logicas{ "expr": "A AND B" }onPOST /rulebooks/— the server requires a full Expr AST since aethis-core 0.7.2. See Author a rule.
Date field values
Date fields are stored internally as integer ordinals (days since year 1). Since aethis-core 0.31.0, /decide and /explain-failure also accept strict ISO date strings on date fields and convert server-side — "2025-04-13" and 739354 are equivalent inputs.
Two caveats:
- Bare
YYYY-MM-DDonly. ISO datetimes ("2025-04-13T00:00:00Z") are not accepted. - Rulebook evaluations still require ordinals. ISO acceptance applies when evaluating a ruleset (
ruleset_id); therulebook_idpath takes integer ordinals only.
"2026-02-30", "next tuesday") does not fail the request: /decide returns 200 with the field named in field_errors and that answer ignored, so the decision is computed from the remaining fields (typically undetermined).
To convert an ISO date to an ordinal yourself:
Source of truth
This page is hand-maintained. The authoritative list ofreason_code values lives in the server source under aethis-core/aethis_core/public/ — grep for reason_code to enumerate. When a new reason_code is introduced, update this page in the same PR.