---
title: "Error catalog"
description: "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."
category: reference
surfaces: [canvas, http-api, console]
related: [getting-started/invoke-via-api, guides/debug-a-flow, reference/http-api, concepts/execution-model, guides/api-keys]
last_reviewed: 2026-06-11
---

# Error catalog

This 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:

```text
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](../guides/debug-a-flow.md) 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: transform TRANSFORM_<NAME> failed: <detail>` | A transform in the edge's adapter failed at runtime — wrong argument count, a non-numeric argument, or an input value it cannot convert. | Open the edge and fix the transform. See [Edge transform errors](#edge-transform-errors) for every transform's error. |
| `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](../concepts/type-system.md). |
| `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 (fan-out, runtime mutation) after the [daily execution quota](../reference/http-api.md#daily-quotas) 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 transform errors

Transforms run inside edge adapters; at runtime a failing transform produces
`transform TRANSFORM_<NAME> failed: <message>` inside an edge error (see
above). The messages per transform function, as written in adapter
expressions:

| Function | Error | Meaning |
|---|---|---|
| `mult` | `multiply needs a multiplier value, e.g. multiply(2)` | No argument given. |
| `mult` | `multiply: "<arg>" is not a number` | Argument is not numeric. |
| `add` | `add needs a value to add, e.g. add(5)` | No argument given. |
| `add` | `add: "<arg>" is not a number` | Argument is not numeric. |
| `mult`, `add` | `cannot convert <type> to float` | The input field's value is not numeric. |
| `suffix` | `suffix needs a string to append, e.g. suffix(" world")` | No argument given. |
| `prefix` | `prefix needs a string to prepend, e.g. prefix("hi ")` | No argument given. |
| `cel` | `cel requires 1 or 2 args (expression[, srcField])` | Wrong argument count. |
| `cel` | `CEL parse error: <detail>` / `CEL evaluation failed: <detail>` | The CEL expression is invalid, or failed against this input. |
| `replace` | `replace requires 2 args (from, to)` | Wrong argument count. |
| `replace` | ``replace: `from` is required`` | Empty `from` argument. |
| `regex_replace` | `regex_replace requires 2 args (pattern, replacement)` | Wrong argument count. |
| `regex_replace` | ``regex_replace: `pattern` is required`` | Empty pattern. |
| `regex_replace` | `regex_replace: invalid pattern: <detail>` | The pattern is not a valid regular expression. |
| `slice` | `slice requires 2 args (start, end)` | Wrong argument count. |
| `split` | `split requires 2 args (sep, index)` | Wrong argument count. |
| `split` | ``split: `separator` is required`` | Empty separator. |
| `split` | `split: index <n> out of range` | Fewer parts than the index asks for. |
| `default` | `default requires 1 arg` | Wrong argument count. |
| `cast` | `cast requires 1 arg (target kind)` | Wrong argument count. |
| `cast` | `cast: "<value>" is not a number` / `cast: cannot convert <type> to <kind>` / `cast: unsupported target kind "<kind>"` | The value cannot be converted to the requested kind, or the kind is not one cast supports. |

`upper`, `lower`, `trim`, and `length` take no required arguments and do not
fail at runtime.

## 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](../reference/http-api.md).

### 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](../guides/api-keys.md). |
| 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](../reference/http-api.md#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:

```json
{
  "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:

```json
{
  "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.

## 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. |
| 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. |

## Execution history and debug API errors

Errors from the execution-history and debugging endpoints (used by
[Debug a flow](../guides/debug-a-flow.md)):

- Execution history and event requests return `404` with
  `{"error":"execution not found"}` when the execution id doesn't exist
  for your tenant.
- `GET /invocations/v1/executions/{id}/checkpoints/{checkpoint_id}` returns
  `404` with
  `{"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: `404` when a memory
  entry or session is not found, `400` for invalid arguments, `403` for
  permission denied, `401` for unauthenticated requests, and `429` when
  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](../concepts/sandboxing-and-tenancy.md).
