Source: docs/integration/errors.md
API errors
The Public API uses JSON errors. The OpenAPI contract is authoritative for the
status and shape of each route.
Most Public API routes return:
{
"error": "Invalid API key",
"code": "UNAUTHORIZED"
}
The HTTP channel returns a structured error object:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid JSON body"
}
}
Recovery guide
| Status | Typical codes | Recovery |
|---|---|---|
400 | VALIDATION_ERROR, INVALID_CREDENTIAL, MANIFEST_INVALID | Fix the request using the OpenAPI schema; do not retry unchanged input. |
401 | UNAUTHORIZED | Confirm the API key and base URL belong to the same environment; ask the administrator to reissue the bundle if needed. |
404 | CAPABILITY_NOT_FOUND, CREDENTIAL_NOT_FOUND | Confirm the identifier belongs to the current access bundle. |
405 | METHOD_NOT_ALLOWED | Use the method documented for the route. |
409 | CONFLICT, IDEMPOTENCY_KEY_REUSED, REVISION_CONFLICT, CAPABILITY_DISABLED, CREDENTIAL_NOT_CONFIGURED | Re-read the capability, use the current If-Match revision for an update or explicit state transition, and retry only after correcting the request. |
502 | CAPABILITY_EXECUTION_UNAVAILABLE, UPSTREAM_* | Inspect the bounded error body. Forgium never executes host-owned operations; UPSTREAM_* codes indicate endpoint or transport failure. |
413 | REQUEST_TOO_LARGE | Reduce the credential request to the documented limit. |
422 | VALIDATION_ERROR | Send a text message with a non-empty body and valid fields. |
500 | AGENT_RUNTIME_ERROR, INTERNAL_ERROR | Apply the host application's retry policy and retain the response code for support. |
503 | CREDENTIAL_VAULT_UNAVAILABLE, POLICY_UNAVAILABLE | Do not retry credential rotation repeatedly; retry other temporary service failures according to the host policy and contact the operator if they persist. |
Never log API keys, endpoint tokens, authorization headers, or complete request
bodies containing secrets. For a suspected leak, stop and request rotation.
Capability runtime behavior
These are observable agent behaviors, not HTTP error codes. They describe how
the agent handles capability-related situations in conversation.
Missing arguments
When the user's message does not include a required argument for a capability,
the agent should ask for clarification rather than fabricating the value.
User: "Obtener las unidades funcionales."
Agent: "¿De qué consorcio querés consultar las unidades?"
The agent must not invent IDs, names, or other operational arguments to fill
missing fields.
No matching capability selected
When the user's request does not match any active capability (by topic, intent,
or available schema), the agent responds without calling a capability. This is
not an error — it is the expected behavior for out-of-scope or unsupported
requests.
User: "¿Cuál es la capital de Uruguay?"
Agent: "La capital de Uruguay es Montevideo."
If a model proposes a capability whose declared explicit exclusion matches the
request, the runtime also fails closed without contacting the endpoint. The
trace shows the selected candidate, an unresolved coverage_gap, and the
terminal safe_fallback; the exclusion cannot broaden authorization or
change account policy.
Capability execution failure
When the upstream endpoint returns an error (timeout, 5xx, unauthorized), the
agent communicates the unavailability without inventing data.
User: "Obtener las unidades del consorcio Torres del Agua."
Agent: "No pude consultar esa información en este momento. Por favor, intentá de nuevo."
The agent must not claim the consorcio does not exist, fabricate units, or
expose internal error codes to the user.
Host-owned operation result
Forgium does not approve or execute mutations. The host application owns
confirmation, authorization, concurrency, idempotency, and mutation. It may
report a terminal status through the operation-results endpoint after the host
operation finishes.
Empty result
When the capability returns a valid but empty result (e.g., a consorcio exists
but has no units), the agent reports the absence without treating it as an error.
User: "Obtener las unidades del consorcio Torres del Parque."
Agent: "No hay unidades registradas para Torres del Parque."
One capability per turn
The current runtime executes at most one capability per turn. This is a
platform limit, not an error. If a request needs another operation, only the
first matching capability is executed in the current turn. Structure the
conversation so each turn requests a single operation.
Current-run diagnostics
When present in a successful HTTP-channel response, capability_trace.events
uses stable statuses rather than model reasoning: not_selected, unresolved,
selected, arguments_invalid, execution_failed, empty_result,
result_received, response_generated, and runtime_failed. A
reason_code is a bounded technical category, not an explanation of why a
model made a decision. In particular, safe_fallback identifies the terminal
safe-response path, not its cause; inspect the preceding event. A
runtime_failed event distinguishes selection_inference_failed from
grounded_inference_failed.
The trace never includes prompts, chain-of-thought, message text, arguments,
result bodies, credentials, complete signed context values, headers, or stack
traces. It covers only the run returned by that response; use the opaque
run_id or benchmark_observation.correlation_id when contacting support.
See Current-run capability diagnostics
for the complete status, reason-code, selection, grounding, and diagnostic
semantics.