# Execution Failures

> Applies to: ChengOS v0.1.0+ ｜ Last verified: 2026-08-12 ｜ Source: `crates/cheng-engine`, `crates/cheng-api/src/rest/handlers/execution`, `crates/cheng-api/src/ws/protocol.rs`

The system installs and the editor works, but a run does not do what you expect. This page is the
diagnostic path.

## The method

Almost every execution failure resolves by answering one question first: **did the failing node
receive the inputs you thought it would?**

1. Open the execution and click the failed node.
2. Read the error **and the inputs it actually received**.
3. If the inputs are wrong, the problem is upstream — follow the edge back and inspect that
   node's output.
4. If the inputs are right, the problem is that node's configuration or an external service.

That ordering matters because a node reporting a confusing error is usually a node that was handed
something unexpected. Debugging the error message before checking the inputs is how people lose
an afternoon.

## Where to look

| Source | Contents |
|---|---|
| Failed node in the editor | Error plus actual inputs — start here |
| `GET /api/v1/executions/:id` | Status, timings, per-node results |
| `GET /api/v1/executions/:id/logs` | Log output |
| `GET /api/v1/executions/:id/trace-snapshot` | Full structured trace |
| `utils/preview` nodes | Intermediate values while developing |
| `deploy/logs/cheng-api.log` | Server-side errors the run did not capture |

## Reading node states

| State | Meaning |
|---|---|
| `waiting` | Dependencies not satisfied. Stuck here means an upstream node never completed |
| `ready` | Dependencies met, queued |
| `running` | Executing |
| `completed` | Succeeded |
| `failed` | Errored — the one to click |
| `skipped` | A conditional branch routed around it |

`skipped` is frequently correct rather than a fault. If a node you expected to run was skipped,
inspect the `utils/condition_router` upstream and what it actually evaluated — the router did what
its condition said, which may not be what you meant.

## Reading execution states

| State | Meaning |
|---|---|
| `pending` | Created, not started |
| `running` | In progress |
| `paused` | Suspended, resumable |
| `waiting_for_review` | **Not stuck** — waiting for a human decision |
| `completed` / `failed` / `cancelled` / `timeout` | Terminal |

A run sitting in `waiting_for_review` is behaving correctly: a tool returned
`requires_review: true`. Answer it in the editor's approval card, with `/approve` in the CLI, or
via `POST /executions/:id/approve`.

## Common failures

### Model node fails immediately

The single most common first-run failure. In order of likelihood:

1. No credential configured for that provider.
2. A model name the provider does not recognise.
3. A provider capability the workflow assumes but the provider does not declare — notably, an
   agent with `use_function_calling = true` against **Anthropic or Ollama**, which do not declare
   native tool calling. See [model configuration](/docs/config-llm-models).
4. A local model endpoint blocked because `ALLOW_PRIVATE_LLM_ENDPOINTS=false`.
5. Rate limiting or quota exhaustion at the provider.

### A field you configured is ignored

Something is wired into that input port. **An edge wins over a typed value** — the field renders
as a read-only "connected" indicator precisely to signal this. Delete the edge if you meant to
type a literal.

### `{{variable}}` appears literally in the output

The name does not match any reachable upstream output. Use the variable selector rather than
typing names; it lists what is genuinely available at that point in the graph.

### The run will not start

An execution is already `running`, `paused`, or `waiting_for_review` for that workflow. Cancel or
resolve it first. `GET /executions/active` lists what is holding the slot.

### Timeout

Node tasks have a 300-second default timeout. A run in `timeout` state means a node exceeded its
budget — usually a slow external API, an over-large model request, or a shell command waiting on
input that never comes. Split the work, or reduce what the node is asked to do in one step.

### Sandbox and file errors

File tools are confined to the workspace sandbox. Errors here mean:

- The path is outside the sandbox.
- `CHENG_CLI_ALLOWED_ROOTS` is unset (CLI sessions disabled entirely).
- The CLI and API do not see the path in the same filesystem namespace.
- The session is read-only (`--read-only`).

### Code node unavailable

Check `CHENG_ENABLE_CODE_PYTHON` and `CHENG_ENABLE_CODE_JS`.

## Agent-specific failures

An agent that fails needs the event stream, not just the `trace` output — the trace tells you what
happened, the stream tells you where it is stuck. Watch `AGENT_ITERATION_COMPLETED`,
`TOOL_EXECUTION_*`, and `CONTEXT_WINDOW_STATUS_UPDATED`.

| Symptom | Likely cause |
|---|---|
| Stops before finishing | `max_iterations` exhausted. In `short` mode it pauses to ask you; raise the budget or switch to `long` |
| Loops without progressing | `long` mode's no-progress policy should stop it. Check the task is actually achievable with the tools given |
| Cannot find a tool | Tool not in scope. In Tool Hub `user` mode check `enabled_tools`; in `skill` mode the Skill's `tool_hub.tools` declaration governs |
| "Ambiguous skill binding" | Several Skills were described in one loop. Tool Hub rejects rather than guessing — pass `skill_name` explicitly |
| Repeats the same read | Redundant-read suppression is working; the agent is being discouraged from re-reading. Usually a prompt problem |
| Context overflow | History exceeded the window. Compaction handles most cases; use `/compact` in the CLI, or a larger-context model |

## Recovering and retrying

Cancel with `POST /executions/:id/cancel`. Retrying a failed execution resumes from the point of
failure and produces a **new execution id** — the failed record stays intact as evidence rather
than being overwritten.

Traces are durable, so closing the browser does not lose a long agent run. The editor rejoins the
stream on reconnect. If the stream goes silent for 30 seconds, clients reconcile against the API
instead of waiting indefinitely — so a spinner that never resolves is a client problem, not
necessarily a stuck run.

## When everything returns 403

`403 DEMO_MODE_RESTRICTED` means `CHENG_DEMO_MODE=true`, which denies executions and writes by
allowlist. That is configuration, not permissions.

## Next steps

- [Execution model](/docs/exec-model) — why nodes run in the order they do.
- [Testing and debugging](/docs/editor-testing-debug) — the editor's tools.
- [Installation problems](/docs/fix-install-issues) — when it is the install, not the run.
