Skip to content

Error Codes

Frank Yglesias Bertheau edited this page Jul 7, 2026 · 1 revision
<h1>ᚾ&nbsp;NornGate — Error Codes</h1>

Every denial carries an HTTP status, a stable type URN, the deciding gate, and the requestId. This page is the catalogue: what each code means, why it fired, and what to do about it.


ᚺ Overview

Errors have two origins — do not conflate them:

  • Gate denials — NornGate stopped the request at a gate. These are the codes below, always fail-closed, always in application/problem+json (RFC 9457) with a gate field.
  • Upstream passthrough — on ALLOW, the target service's own response flows back unchanged. A 404 or 422 from your service is not a gate denial and carries no gate field; look to your service, not the gates.
{
  "type": "urn:norngate:error:policy-denied",
  "title": "Policy denied",
  "status": 403,
  "detail": "agent role cannot access resource type 'model'",
  "gate": "policy",
  "requestId": "req_abc123"
}

The presence of gate is the tell: if it is there, a NornGate gate denied you; if not, it is your upstream.


ᛁ The catalogue

Two failure modes: a denial (the gate evaluated and refused) and a timeout (the gate could not decide in its budget; circuit breaker trips). Both fail-closed.

Code type (urn:norngate:error:…) Gate Mode Retryable
400 malformed-request G0 denial no
401 unauthenticated G0 denial after re-auth
403 policy-denied / approval-denied G1 / G2 denial no (as-is)
408 approval-timeout G2 timeout conditional
409 write-conflict G4 denial + timeout yes (backoff)
429 rate-limited G0 denial yes (Retry-After)
500 sandbox-failure G3 denial + timeout only if transient
503 gate-unavailable G0 / G1 timeout yes (backoff)

References. RFC 9457 (Problem Details for HTTP APIs); RFC 9110 (HTTP semantics — status codes, Retry-After). Naming doctrine: Prose Edda / Poetic Edda, per Norse Cosmology & Platform Design.

ᚾ NornGate — Error Codes

Every denial carries an HTTP status, a stable type URN, the deciding gate, and the requestId. This page is the catalogue: what each code means, why it fired, and what to do about it.


ᚺ Overview

Errors have two origins — do not conflate them:

  • Gate denials — NornGate stopped the request at a gate. These are the codes below, always fail-closed, always in application/problem+json (RFC 9457) with a gate field.
  • Upstream passthrough — on ALLOW, the target service's own response flows back unchanged. A 404 or 422 from your service is not a gate denial and carries no gate field; look to your service, not the gates.
{
  "type": "urn:norngate:error:policy-denied",
  "title": "Policy denied",
  "status": 403,
  "detail": "agent role cannot access resource type 'model'",
  "gate": "policy",
  "requestId": "req_abc123"
}

The presence of gate is the tell: if it is there, a NornGate gate denied you; if not, it is your upstream.


ᛁ The catalogue

Two failure modes: a denial (the gate evaluated and refused) and a timeout (the gate could not decide in its budget; circuit breaker trips). Both fail-closed.

Code type (urn:norngate:error:…) Gate Mode Retryable
400 malformed-request G0 denial no
401 unauthenticated G0 denial after re-auth
403 policy-denied / approval-denied G1 / G2 denial no (as-is)
408 approval-timeout G2 timeout conditional
409 write-conflict G4 denial + timeout yes (backoff)
429 rate-limited G0 denial yes (Retry-After)
500 sandbox-failure G3 denial + timeout only if transient
503 gate-unavailable G0 / G1 timeout yes (backoff)

ᛒ Cause and remedy

Code Cause Remedy
400 Missing fields, bad schema, oversized body Fix the request shape; validate before sending.
401 No valid SPIFFE SVID (mesh) or bearer token/API key (external) Re-authenticate; check the SVID is issued and unexpired, or refresh the token.
403 No allow rule matched, a deny rule matched (deny-overrides), or required approval was refused Adjust policy for the (identity, resource, action) tuple, or obtain the approval; inspect the record to see which rule fired.
408 A human approval was required and no decision arrived within 30s Re-submit with the same Idempotency-Key; the approver may decide on a later attempt. Consider a standing automated-consent policy to cut human transits.
409 Another writer holds the resource lease, or the G3 fencing token was stale at commit Retry with backoff and the same Idempotency-Key; the lease frees or the state is re-read.
429 Per-identity/tenant rate limit exhausted at G0 Honor Retry-After; smooth request rate; request a higher limit if legitimate.
500 Sandbox validation failed, a disallowed effect was produced, or VM allocation failed If the effect was disallowed, fix the action (do not retry blindly). If it was a transient allocation failure, retry with backoff.
503 A gate (policy store, engine) could not respond within its budget Retry with backoff; this is a transient dependency outage — the fleet is failing closed, not failing open.

ᛖ Retry policy

  • Always retry 503 and 409 with exponential backoff; 429 per its Retry-After header.
  • Conditionally retry 408 (a human may approve next time) and 500 (only if the cause was transient allocation, not a disallowed effect).
  • Do not retry 400, 401, or 403 unchanged — the input, identity, or policy must change first.
  • Retries are safe for any request carrying an Idempotency-Key: the side effect commits exactly once at G4 regardless of delivery count ([Deterministic Execution](Deterministic-Execution)). Never retry a state-changing request without one.

ᚲ How to read a denial

A denial is a queryable fact, not a dead end. Take the requestId and resolve it:

GET /v1/audit?requestId=req_abc123

The decision record names the deciding gate, the matched rules (by reference), and the pinned policy / state / config snapshot IDs. From there, norngate-cli audit replay req_abc123 re-derives the verdict against those exact inputs — so "why was this denied?" always has a reproducible answer. Record shape: [Urd Ledger](Urd-Ledger).


ᚱ Next steps

  • [API Reference](API-Reference) — the problem+json contract and headers.
  • [The Five Gates](The-Five-Gates) — what each gate checks and why it denies.
  • [Urd Ledger](Urd-Ledger) — the record behind every denial.
  • [Reference](Reference) — quick-reference tables.

Iconography

Section glyphs are Elder Futhark runes (Unicode Runic block, U+16A0–U+16FF) — semantic, not emoji. Full set on [Home](Home#iconography):

Rune Name Gloss Marks
Nauðiz need, constraint the platform mark
Hagalaz hail, failure states overview
Isa ice, the fixed catalogue the codes
Berkanan growth, remedy cause & remedy
Ehwaz the journey retraced retry policy
Kenaz the torch, looking into reading a denial
Raidō the ride, the road next steps

References. [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) (Problem Details for HTTP APIs); [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) (HTTP semantics — status codes, Retry-After). Naming doctrine: Prose Edda / Poetic Edda, per [Norse Cosmology & Platform Design](Norse-Cosmology-and-Platform-Design).

Clone this wiki locally