Skip to content

Errors

Shape

Errors come back as JSON with three fields:

json
{
  "statusCode": 400,
  "message": "size must be one of small | medium | large; got 'extra-large'",
  "error": "invalid_size"
}
  • statusCode — the HTTP status code, repeated in the body.
  • message — human-readable. Safe to surface in CI logs.
  • error — short machine-readable code for branching. Stable across versions; the message may be edited.

For validation errors (400), message is sometimes an array of per-field issues:

json
{
  "statusCode": 400,
  "message": [
    "slug must be 2–40 chars, lowercase alphanumerics + dashes",
    "adminEmail must be an email"
  ],
  "error": "Bad Request"
}

Status code guide

StatusWhat it meansWhat to do
400 Bad RequestValidation failed — wrong types, missing fields, bad enumsFix the request. The message array tells you which fields.
401 UnauthorizedMissing, invalid, or expired tokenMint a new token; check Authorization header is set.
403 ForbiddenAuthenticated but not allowed — wrong role, missing scope, federation/spoke not in your visibilityCheck the token's scope and the user's role.
404 Not FoundThe resource doesn't exist or you can't see itWe return 404 instead of 403 when the existence of the resource is sensitive.
409 ConflictThe request would violate a uniqueness or lifecycle invariantE.g. signing up with an email that's already in use; trying to provision a spoke at a slug already taken.
422 Unprocessable EntityReserved — currently unusedIf you see this, it's a bug. Report it.
429 Too Many RequestsHit a rate limitBack off. See Rate limits.
500 Internal Server ErrorThe control plane itself failedCheck /api/healthz. Open a ticket if it persists.
502/503/504Ingress / load sheddingRetry with exponential backoff.

Common error codes

A non-exhaustive list of error codes you might see:

CodeStatusMeaning
invalid_size400The size field wasn't one of small/medium/large
federation_id_mismatch400Path :federationId doesn't match the body's federationId
email_taken409Signup attempted with an in-use email
hub_not_found404The federation has no hub provisioned yet
unauthorized401Generic auth failure — wrong/missing token
forbidden_scope403Token lacks the scope required for this endpoint

Codes are added as endpoints are added. We don't promise the full list is documented; treat unknown codes the same way you treat the matching status.

Idempotency and retries

Most POST endpoints are not idempotent by default — provisioning a spoke twice creates two spokes if the slugs differ. The exceptions are documented per-endpoint in the reference. If you need at-most-once semantics, take the lock on your side or check existence with a GET before posting.

Network-level retries (e.g. retrying a 5xx) are safe for GET and DELETE. For POST/PATCH, only retry when you're confident the request didn't reach the server (connection refused, DNS fail).

Released under the GPL v3 license.