Error catalog
Every user-facing Axiom error — flow run failures in the editor, edge transform errors, and HTTP API error responses — with what causes each one and how to fix it.
View as MarkdownThis page lists the errors Axiom shows users, grouped by where you see them: in the editor when a flow run fails, and in HTTP responses when you call the API. Each entry gives the exact error shape, the cause, and the fix.
How errors name nodes and edges
Flow run errors identify nodes by their canvas id — the per-placement id
you see on the node card in the editor (for example id-bad or
node-1716492048192) — never by the marketplace node name. This matters
when a flow contains two placements of the same node: the error names the
specific placement that failed, so you can find it on the canvas directly.
Edges are named by quoting both endpoints. An edge error reads:
edge "id-bad" → "echo-merge": EvaluateEdge adapter: transform TRANSFORM_PREFIX failed: prefix needs a string to prepend, e.g. prefix("hi ")Here id-bad and echo-merge are the canvas ids of the edge's source and
destination nodes.
When a failure is attributed to a specific edge or node, the result panel at
the bottom of the editor also shows the failure kind (for example
EDGE_ADAPTER) and a Show on canvas button. Clicking it selects the
offending edge — or node, when the failure has no edge attribution — on the
canvas so you can open and fix it. See
Debug a flow for the full debugging workflow.
Flow run errors in the editor
When an execution fails, the flow status pill above the canvas shows Failed, the result panel header shows Execution Failed, and the panel's Output tab contains the error text. The errors you can see:
| Error | Cause | Fix |
|---|---|---|
edge "<src>" → "<dst>": EvaluateEdge adapter: <detail> | The edge's adapter (a bare CEL expression) failed to compile or evaluate at runtime — a parse error, a type mismatch, or an eval error. | Open the edge and fix the CEL expression. See Edge adapter (CEL) errors. |
edge "<src>" → "<dst>": EvaluateEdge condition: <detail> | The edge's condition expression failed to evaluate (for example CEL evaluation failed: …). | Fix the condition expression on that edge. |
invalid JSON for <InputType>: <detail> | The JSON input you submitted does not match the entry node's input message — unknown field, wrong type. | Match the field names and types of the entry node's input message. See Type system. |
graph produced no terminal result | The execution ended without the terminal node producing output — typically every outgoing edge condition evaluated to false somewhere along the path. | Check edge conditions; make sure at least one path reaches the terminal node for this input. |
exceeded max steps (1000) | The execution dispatched more than 1000 node steps — almost always a loop that never meets its exit condition. | Fix the loop's exit condition. |
... daily executions quota exceeded (cap <n>) | The flow tried to spawn child executions (parallel branches, runtime mutation) after the daily execution quota ran out; the whole flow fails. | Wait for the midnight-UTC reset, or ask the operator for a higher limit. |
downstream join <n> failed: <reason> | A node feeding a join failed, and the join's failure policy aborted the flow. | Fix the failing branch, or relax the join's failure policy. |
open pipeline stream for node "<id>", send to node "<id>", recv from node "<id>" | In pipeline mode, the platform lost the connection to that node's container. | Usually transient — re-run; if it persists, check the node's logs. |
When your own node code raises an exception, the handler's error message is
surfaced verbatim: it appears on the NODE_FAILED event in the result
panel's Execution tab, attributed to the failing placement's canvas id.
Edge adapter (CEL) errors
An edge adapter's right-hand side is a bare CEL expression (or a plain field pick) evaluated against the source message. A failing expression produces a CEL error inside an edge error (see above). The failure modes:
| Stage | Error | Meaning |
|---|---|---|
| Parse | CEL parse error: <detail> | The expression is not syntactically valid CEL. |
| Type-check / compile | CEL compilation failed: <detail> (e.g. no matching overload, undeclared reference) | The expression is well-formed but ill-typed — e.g. text + 1 mixes string and int, or it references a field/function that is not in scope. |
| Eval | CEL evaluation failed: <detail> | The expression compiled but failed against this input — e.g. an index out of range or a division by zero. |
CEL string helpers such as toUpper, toLower, trim, size, and join
are available in the adapter scope; call them directly (toUpper(text)), not
through a pipe. A destination field path (the mapping key) that contains
( or ) is rejected at compile time as a malformed field name.
Whole message-typed field picks copy the message byte-for-byte, so they are only valid between the same message type. These are rejected at compile time (never at run) — the fix is to reconstruct the destination in CEL, field by field:
| Error | Meaning | Fix |
|---|---|---|
adapter: field pick "<src>" maps message type "<A>" into differently-typed message field "<dst>" (type "<B>") … | A whole-message pick across two different message types — a verbatim byte copy would misread the wire. | Map each leaf field explicitly in CEL ("<dst>.field": "<src>.field"), or use a CEL object literal, so the reshape is declared. |
adapter: field pick "<src>" maps a <kind> value into <kind> field "<dst>" … cannot convert between a message and a scalar … | A pick tried to bridge a message field and a scalar field. | Write a CEL expression that constructs the destination shape. |
adapter: field pick "<src>" maps a <repeated/singular> message into a <singular/repeated> field "<dst>" … requires matching cardinality … | A whole-message pick with mismatched cardinality (a repeated message into a singular field, or vice versa). | Reshape in CEL (e.g. index a single element, or map(…) a list). |
HTTP API errors when invoking a flow
Errors from POST /invocations/v1/flows/invoke and its streaming variant.
For the full request/response contract see the
HTTP API reference.
Authentication, rate limiting, and quotas
| Status | Body | Cause | Fix |
|---|---|---|---|
| 401 | {"error":"unauthorized"} | Missing, malformed, revoked, or expired credentials on any authenticated route. | Send a valid key in the Authorization: Bearer header — see Create and manage API keys. |
| 429 | {"error":"rate limit exceeded"} | Your tenant exceeded the per-tenant invocation rate limit (per-second burst). The response carries a Retry-After: 1 header. | Back off and retry after the indicated delay. |
| 429 | {"error":"quota_exceeded", "retry_after_seconds": ...} | Your tenant exhausted one of its daily quotas — invocations or executions. The message names which; retry_after_seconds counts down to the reset at midnight UTC. | Wait for the daily reset, or ask the operator to raise your tenant's limit. |
| 403 | {"error":"tenant_suspended"} | Your tenant has been disabled by the operator. All invocations and resumes are rejected. | Contact the operator. |
| 503 | {"error":"quota_unavailable", "retry_after_seconds": 5} | The quota service could not be reached, so the request was rejected as a safety measure. | Transient — retry after the indicated delay. |
Structured invoke errors
Invoke failures with a known cause return a structured body:
{
"error": "payload_too_large",
"message": "payload exceeds hard cap: actual=17825792 max=16777216",
"max_bytes": 16777216,
"actual_bytes": 17825792
}| Status | error class | Cause | Fix |
|---|---|---|---|
| 413 | payload_too_large | The input exceeds the 16 MiB hard cap (max_bytes/actual_bytes populated). | Shrink the input payload. |
| 503 | upstream_unavailable | The flow could not be queued; a platform dependency was temporarily unavailable. retry_after_seconds: 5. | Transient — retry after the indicated delay. |
| 503 | blob_storage_unavailable | A large input payload could not be stored; a platform dependency was temporarily unavailable. retry_after_seconds: 5. | Transient — retry after the indicated delay. |
Failures that don't classify return 500 with
{"accepted": false, "error_message": "<detail>"}.
Timeouts
With "wait": true, if the execution does not complete within the timeout
(default 30 seconds), the response is still 202 — the execution keeps
running:
{
"accepted": true,
"execution_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"error_message": "timeout waiting for flow result (30s)"
}Set "timeout_seconds" to wait longer, or look the execution_id up later
in execution history. On the streaming endpoint, a timeout ends the stream
with a final frame whose error is "timeout waiting for pipeline result";
a flow that fails mid-stream ends with a final frame whose error carries
the flow run error described above.
A request that is accepted and delivered but whose execution runs to a
failure (for example, the input did not match the flow's start-node schema)
returns HTTP 202 with "result":{"success":false,...} and surfaces the
worker's diagnostic in both result.error_message and the top-level
error_message — so a synchronous caller can tell a delivered failure apart
from a timeout or transport error without polling execution history.
HTTP API errors when invoking a single node
Errors from the per-node JSON endpoint
POST /invocations/v1/nodes/{owner}/{pkg}/{version}/{node} (also accepts a
node id in place of the name path):
| Status | Body | Cause | Fix |
|---|---|---|---|
| 404 | {"error_message":"node not found or not yet deployed"} (or node not found: <detail> for a name path that doesn't resolve) | The node id or {owner}/{pkg}/{version}/{node} path doesn't match a published, deployed node. | Check the package name, version, and node name against the marketplace listing. |
| 400 | {"error_message":"invalid JSON for <InputType>: <detail>"} | The JSON body doesn't match the node's input message. | Match the input message's field names and types. |
| 400 | {"execution_id":"...","error_message":"invalid value for <InputType>: field \"<name>\" carries enum ordinal <n>, which names no declared value ..."} | An enum field is set to an ordinal that is not a declared value of its enum — typically a payload recorded before the field was an enum (or against a different schema version). | Re-record the payload against the node's current schema. |
| 422 | {"error_message":"<detail>"} | The node ran and its handler returned an error — error_message is the handler's own message. | Fix the input, or the node code. |
| 502 | {"error_message":"could not connect to node"} / "calling node: <detail>" / "sending to node: <detail>" | The platform could not reach the node's container. | Usually transient (cold start) — retry; if it persists, check the node's deployment. |
The binary-protobuf variant POST /invocations/v1/nodes/invoke validates its
base64 payload against the node's current input schema before forwarding:
bytes whose wire shape doesn't match (an undeclared field number, or a wire
type conflicting with the declared kind), or any payload whose node schema
can't be resolved, return HTTP 400 with
{"success":false,"error_message":"payload does not match the node's current input schema: <detail>"}.
HTTP API errors when pre-warming a flow
Errors from POST /invocations/v1/flows/warm (see
Pre-warm a flow). Authentication,
rate-limit, and quota failures return the same bodies as
invoking a flow above — a warm
debits the same daily invocation quota an invoke does. Pre-warm adds these
ownership and availability cases:
| Status | Body | Cause | Fix |
|---|---|---|---|
| 400 | {"error":"invalid_request","message":"..."} | graph_id is missing or doesn't match [A-Za-z0-9_-]+. | Pass a valid graph_id. |
| 403 | {"error":"forbidden","message":"not authorized to warm this flow"} | The authenticated tenant does not own graph_id. | Warm a flow your tenant owns; a foreign graph_id is never accepted, even to pre-warm it. |
| 404 | {"error":"not_found","message":"flow not found"} | graph_id doesn't resolve to any flow. | Check the id against the flow's Use via API dialog. |
| 503 | {"error":"warm_unavailable","message":"...","retry_after_seconds":5} | The warm dispatcher isn't configured on this deployment. | Transient/deployment-specific — retry after the indicated delay, or invoke the flow directly instead. |
Execution history and debug API errors
Errors from the execution-history and debugging endpoints (used by Debug a flow):
- Execution history and event requests return
404with{"error":"execution not found"}when the execution id doesn't exist for your tenant. GET /invocations/v1/executions/{id}/checkpoints/{checkpoint_id}returns404with{"error":"checkpoint_not_found_or_expired","detail":"checkpoint may have been evicted by TTL policy (default 30d)"}— checkpoints expire after a retention window (default 30 days), so debug a recent execution instead.- Agent memory operations return standard statuses:
404when a memory entry or session is not found,400for invalid arguments,403for permission denied,401for unauthenticated requests, and429when resource limits are exhausted.
All endpoints are tenant-scoped: a valid id belonging to another tenant
behaves exactly like a nonexistent one (404), never 403 — see
Sandboxing and tenancy.