Errors use a structured envelope.
{
"error": {
"code": "schema_validation_failed",
"type": "invalid_request",
"message": "Request body failed schema validation.",
"doc_url": "https://docs.havilo.ai/reference/ai-engine/errors#schema_validation_failed",
"request_id": "req_01hxbexample",
"param": "query",
"details": {
"issues": [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["query"],
"message": "Required"
}
]
}
}
}| Field | Always present | Description |
|---|---|---|
code | Yes | Machine-readable error code. Stable across API versions. |
type | Yes | Broad error category. |
message | Yes | Human-readable description. Do not parse this string. |
doc_url | Yes | This page, at the heading for the code. |
request_id | Yes | The same id as the X-Request-Id response header: yours if you sent one. Quote it to support. |
param | No | The request field that caused the error. For validation errors, the dot-joined path. |
details | No | Code-specific data. Its shape depends on code. |
Retry guidance
Retry only 429, 500, 503 and 504, with exponential backoff, keeping the same Idempotency-Key
when retrying POST /runs. Anything else needs a changed request first.
Request errors
invalid_json
400. The body is not valid JSON, or could not be read.
unsupported_input_type
400. input_type is not query, plan or preset.
unsupported_preset
400. The preset does not exist. The only preset is dossier.
payload_too_large
413. The request body is over 1 MB, counted in bytes.
schema_validation_failed
422. The body or a query parameter has the wrong shape. param names the first failing field and
details.issues lists every failure, each with path as an array. A plan step with a param its kind
does not take fails here too, so a misspelled param is never silently ignored.
missing_required_field
422. A required field is missing; param names it.
query_ambiguous
422. The query has more than one reasonable reading. details.reason says what needs clarifying.
Rephrase it, or submit an explicit plan.
entity_ambiguous
422. The query names a record Havilo cannot pin down. details.question says what to confirm and
details.candidate_ids lists the records it considered, when it found any. Resolve them with
GET /entities/resolve, then send the query again naming the record, or run a plan or the
dossier preset with { "id": "<uuid>" }.
{
"error": {
"code": "entity_ambiguous",
"type": "invalid_request",
"message": "Multiple entity matches found — confirmation required",
"doc_url": "https://docs.havilo.ai/reference/ai-engine/errors#entity_ambiguous",
"request_id": "req_01hxbexample",
"details": {
"question": "Which Acme do you mean: Acme Corp or Acme Holdings?",
"candidate_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"661f9511-f3ac-52e5-b827-557766551111"
]
}
}
}entity_not_resolvable
422. The record reference matches no active record in the workspace. A dossier on such a record is
refused before a run is created, with param: "params.entity".
plan_too_large
422. plan.steps has more than 50 steps. Split the plan into several runs.
{
"error": {
"code": "plan_too_large",
"type": "plan_error",
"message": "The plan exceeds the maximum allowed size.",
"doc_url": "https://docs.havilo.ai/reference/ai-engine/errors#plan_too_large",
"request_id": "req_01hxbexample",
"param": "plan.steps",
"details": { "max_steps": 50, "received": 51 }
}
}invalid_callback_url
422. config.callback_url is not HTTPS or points to a disallowed address. details.reason says
which.
invalid_rerun_step
422. The step index passed to rerun is out of range for the run.
Authentication and access
auth_missing
401. The Authorization header is missing or is not Bearer <key>.
auth_invalid
401. The API key is unknown or revoked, or an event token is malformed or belongs to another run.
auth_expired
401. The API key has expired, or an event token has. For a stream, request a new token with
POST /runs/{id}/events/token.
forbidden_feature
403. The key lacks a scope, or the workspace lacks a feature. details.required_scope or
details.required_feature names it.
forbidden_workspace
403. The key cannot act in this workspace.
Not found
run_not_found
404. The run does not exist or is not visible to this key.
artifact_not_found
404. The artifact does not exist or is not visible to this key.
checkpoint_not_found
404. No saved data exists for that step of the run.
workspace_not_found
404. The workspace does not exist or is not visible to this key.
Conflicts
idempotency_key_conflict
409. The same Idempotency-Key was used with a different body. Retry with the original body, or
use a new key.
{
"error": {
"code": "idempotency_key_conflict",
"type": "conflict",
"message": "Idempotency key reused with a different request body.",
"doc_url": "https://docs.havilo.ai/reference/ai-engine/errors#idempotency_key_conflict",
"request_id": "req_01hxbexample",
"param": "Idempotency-Key",
"details": {
"original_run_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
}canceled_by_user
Not an HTTP error. A canceled run carries it in the run's errors[], with details.step_index set
to the step it stopped at. A run canceled mid-step finishes that step first; until it has, the code
carries no details.
{ "code": "canceled_by_user", "type": "conflict", "details": { "step_index": 2 } }run_not_resumable
409. The run cannot be resumed in its current state. Only failed runs resume; a canceled run does
not. rerun-from also returns it, with details.reason: "no_saved_plan", for a run started from a
query: it has no saved plan to rerun from.
plan_fingerprint_mismatch
409. The plan changed since the run was created, so it cannot resume.
Limits
concurrent_runs_exceeded
429. Too many runs are in flight for the workspace. Retry when one finishes.
workspace_cost_cap_exceeded
429. The workspace's daily cost cap is reached. Retry after the day resets (UTC).
cost_threshold_exceeded
429. The key's daily cost limit is reached. Retry after the day resets (UTC).
Server errors
internal_error
500. Unexpected server error. Retry, and quote request_id if it persists.
model_unavailable
503. The AI model is temporarily unavailable. Retry.
usage_accounting_unavailable
503. Havilo could not price AI usage for the workspace, so no run was started. Retry later.
upstream_timeout
504. A service Havilo depends on timed out, including understanding a query past 45 seconds.
Retry, or submit an explicit plan.
Other Havilo APIs
Havilo's other APIs use the same envelope. These codes come from them; the AI Engine API never sends them.
field_memo_not_found
404. The field memo does not exist.
calendar_event_not_found
404. The calendar event does not exist.
meeting_bot_session_not_found
404. The meeting bot session does not exist.
prepared_email_not_found
404. The prepared email is not waiting in the mailbox.
calendar_event_not_toggleable
409. Meeting bots cannot be switched on or off for this calendar event.
meeting_bot_session_not_stoppable
409. This meeting bot session cannot be stopped.
meeting_bot_session_not_retryable
409. This meeting bot session's post-meeting processing cannot be retried.
rate_limit_exceeded
429. Too many requests. Back off and retry.