Harmont docs
APIErrors

Errors

One JSON envelope for every failure — stable code, human message, and a link to the fix.

Every non-2xx response from the Harmont API uses the same JSON envelope. Scripts match on code, humans read message, and doc_url points at the page for that exact error.

{
  "error": {
    "type": "invalid_request",
    "code": "passkey_unknown_credential",
    "message": "This passkey is not registered. Try a different passkey or use recovery.",
    "doc_url": "https://docs.harmont.dev/api/errors/passkey_unknown_credential",
    "request_id": "req_01H..."
  }
}
FieldNotes
typeClosed-set classifier for generic handling (retry, auth prompts). One of invalid_request, not_found, unauthorized, forbidden, conflict, billing, server_error, rate_limited.
codeStable snake_case identifier — the scripting contract. Never renamed in place; new codes are added and old ones aliased.
messageHuman-readable, in the user's voice. No stack traces, no type names.
doc_urlLink to the page for this code (the pages listed in the sidebar).
request_idEchoed from the X-Request-Id response header. Paste it into support requests.

HTTP status follows REST convention: 400 invalid request, 401 unauthenticated, 403 unauthorized, 404 not found, 409 conflict, 402 billing, 429 rate-limited, 5xx server.

Error doctrine

Every Harmont error points precisely, states what was observed, and states the fix. We do not write "did you mean?" — we have the context, so we use it.

  • "Field name is required." — not "Bad request."
  • "Build #14 has already finished and cannot be canceled." — not "Conflict."

Handling errors in clients

Switch on code for behavior; show message to the user; link doc_url:

async function call(url: string) {
  const r = await fetch(url, { headers: { Authorization: `Bearer ${HM_TOKEN}` } });
  if (r.ok) return r.json();
  const { error } = await r.json();
  switch (error.code) {
    case 'passkey_unknown_credential':
      throw new AuthError(error.message, error.doc_url);
    default:
      throw new ApiError(error.type, error.message, error.doc_url);
  }
}

Browse the individual error codes in the sidebar for the cause and fix of each.

On this page