Skip to content

Errors

Every error the API returns is an RFC 9457 problem with content type application/problem+json. Nothing else in the server writes an error body.

{
"type": "https://homestead.app/problems/validation",
"title": "Some fields need attention",
"status": 400,
"code": "validation_failed",
"i18nKey": "errorValidationFailed",
"detail": "handle: must match platform pattern",
"fields": [{ "path": "entries[2].handle", "code": "pattern", "i18nKey": "errorFieldPattern" }]
}
FieldMeaning
typeA URI for the problem type: https://homestead.app/problems/ plus the code with dashes. validation_failed and unknown_field share …/problems/validation.
titleA short human summary. Don’t branch on it.
statusThe HTTP status, repeated.
codeStable and machine-readable. Branch on this.
i18nKeyA key in i18n/*/common.arb to show a localised message: "error" plus the code in PascalCase when that key exists (rate_limited becomes errorRateLimited), otherwise errorGeneric.
detailOptional extra detail, for logs and developers.
fieldsOptional per-field problems, with a JSON-style path, a code and an i18nKey.
  • Branch on code, never on title or detail.
  • Show the localised message for i18nKey. Apps fall back to errorGeneric.
  • On 429 rate_limited, wait for the Retry-After header (seconds) before trying again.
  • On 409 idempotency_conflict, you reused an Idempotency-Key with a different body. Use a new key for a new request.
  • On 501 not_implemented, the operation is in the spec but not built yet on this server.
CodeWhen
validation_failedThe request body or parameters don’t match the schema (400).
unknown_fieldThe request has a field the schema doesn’t define (400).
unauthenticatedNo valid credentials (401).
forbiddenSigned in, but the role isn’t enough, or a cookie write failed the CSRF or origin check (403).
agent_not_allowedAn agent token called an operation agents can’t use (403).
scope_missingThe agent token lacks the scope this operation needs (403).
not_foundThe thing doesn’t exist (404).
conflictThe request conflicts with the current state (409).
already_existsThe account or item already exists.
setup_requiredThe household hasn’t been set up yet.
setup_doneSetup was already run.
rate_limitedToo many requests (429, with Retry-After).
upstream_unavailableA platform or other upstream service didn’t answer.
platform_unsupportedThe platform isn’t in the registry.
share_expiredThe share link has expired.
share_revokedThe share link was revoked.
invite_invalidThe invite code is wrong, used up or expired.
lease_expiredAn agent completed a task after its 10-minute lease ran out.
idempotency_conflictSame Idempotency-Key, different body (409).
payload_too_largeThe upload or body is over the limit (413).
circle_fullThe write would put more than 30 capturable accounts in a circle (409).
capture_closedThe capture no longer accepts uploads.
upload_token_invalidThe hsu_ upload token is wrong, expired or for another capture.
not_implementedThe operation isn’t built yet (501).
internalSomething went wrong on the server. Check its logs.

Some operations report per-item problems inside a 200 reply rather than failing the whole request:

  • Ingest (POST /ingest) stores the valid items and lists the others under rejected, each with an index and a code: invalid_kind, invalid_url, media_host_not_allowed, media_fetch_failed or too_old.
  • Quick-add (POST /quick-add) lists entries it didn’t add under skipped, for example with code already_exists and the existingAccountId.
  • Import preview (POST /imports/preview) gives per-person warnings: platform_unsupported, invalid_handle, invalid_profile_url or no_accounts.