Errors
Every non-2xx response carries the same envelope:
{
"error": { "code": "upstream_unavailable", "message": "...", "details": {} }
}
code and message are always present. Branch on code, which is stable;
message is for people and may change. details (naturali's own errors) or
meta (an error raised by the upstream runtime) carry structured context when
there is any. Advisory fields the upstream runtime attaches to its errors are
not part of this contract and are not relayed.
naturali's own codes are lowercase (access_denied); codes the upstream runtime
raises are uppercase (QUOTA_EXCEEDED). Both arrive in the same envelope.
Codes common to every module
| Status | code | Means |
|---|---|---|
400 | bad_request, or a more specific code | The request is malformed; message says which field. |
401 | unauthorized | Missing, malformed, expired or revoked credential — see Authentication. |
402 | insufficient_credit | The billing owner's balance cannot pay for this work — see Users → Plan and credit. |
403 | access_denied | The credential's scope or the caller's role excludes the action. |
403 | plan_limit_reached, plan_feature_not_included | The billing owner's plan excludes it. details.resource or details.feature names what. |
404 | not_found, or the runtime's own | The resource does not exist, or its project is not one you belong to. |
409 | Varies | A conflicting state, such as a duplicate or a paused project. |
429 | too_many_requests, QUOTA_EXCEEDED, … | A rate limit or a quota — see Rate limits. |
502 | upstream_unavailable | naturali could not complete the call upstream; see below. |
Each operation's page in the API Reference lists the codes it adds, and a module page explains any whose cause is not obvious.
502 upstream_unavailable
A 502 upstream_unavailable is naturali standing in for the upstream runtime,
and its details say what the runtime answered: upstream_status (the HTTP
status) and upstream_code (the runtime's own error code) when it answered at
all, and neither when nothing reached it. That separates a runtime that refused
from a request that never got there.
Reading an error in each client
The CLI prints the envelope to stderr with its status and exits 1. The SDK
never throws on a non-2xx response; it resolves to { data, error }. With
curl, add --fail-with-body to make the exit status reflect it.
- CLI
- SDK
- curl
naturali get-agent \
--project-id proj_V1StGXR8Z5jdHi6B \
--agent-id agent_missing || echo "failed"
const { data, error } = await naturali.agents.getAgent({
path: { project_id: 'proj_V1StGXR8Z5jdHi6B', agent_id: 'agent_missing' },
});
if (error) {
console.error(error.error.code, error.error.message);
}
curl --fail-with-body \
https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/agents/agent_missing \
-H "Authorization: Bearer $NATURALI_TOKEN"