---
title: "Debug a flow"
description: "Start a debug session with breakpoints and pause/step controls, inspect each node's input and output on the canvas, and replay any past execution on its detail page."
category: guide
surfaces: [canvas]
related: [getting-started/first-flow, concepts/execution-model, concepts/nodes-packages-flows, guides/flow-configs, guides/manage-secrets]
last_reviewed: 2026-06-06
---

# Debug a flow

Axiom gives you three debugging surfaces: a **live debug session** started
from the editor (breakpoints, pause, single-step), **payload inspection** on
any node that has executed (its decoded input and output messages), and the
**execution detail page** at `/executions/<id>`, which replays any past
execution event-by-event and lets you fork a new debug session from any
checkpoint.

**Prerequisites:** a saved flow that runs — complete
[Run your first flow](../getting-started/first-flow.md) first. Debug runs
are available for unary flows only; a flow in pipeline mode runs without
the debug controls.

## Start a debug run

In the editor, click **Run** at the bottom-center of the canvas, fill in the
input form in the **Run Graph** dialog, and click **Debug** (the amber
button next to **▶ Run**). Where **▶ Run** simply executes the flow, **Debug**
starts a live debug session: the run honors breakpoints and gives you
manual pause/step controls.

While the session is live, a control bar appears at the bottom-center of
the canvas with three buttons:

- **Pause** — pause the run before the next node is dispatched. Available
  while the run is executing.
- **Continue** — resume a paused run. Replaces Pause while paused; the bar
  gets an amber outline when the run is paused.
- **Step** — execute exactly one node, then pause again. Enabled only while
  the run is paused.

The **Debug** button appears in the Run Graph dialog only for unary flows —
pipeline flows stream frames and cannot be paused node-by-node. See
[Execution model](../concepts/execution-model.md) for the unary/pipeline
distinction.

## Set breakpoints

Right-click any node on the canvas and choose **Set breakpoint**. A red dot
appears on the node; the same menu shows **Clear breakpoint** to remove it.
Breakpoints require a saved flow — on an unsaved flow the menu item shows
"Save the flow first to enable breakpoints." instead of setting one.

When a debug run (started with the **Debug** button) reaches a node that has
a breakpoint, the run pauses before that node executes. The bottom-center
control bar switches into its paused state: **Step** becomes enabled and
**Continue** replaces **Pause**. Step through node-by-node, or click
Continue to run until the next breakpoint or the end of the flow.

Once at least one breakpoint is set, a **Breakpoints** tab appears in the
result panel below the canvas. It lists every breakpoint for the open flow
with the node name and package, a per-row **Clear** action, and a
**Clear all** button. Breakpoints only affect runs started with **Debug** —
plain **▶ Run** ignores them.

## Inspect a node's input and output

After a node has executed — successfully or with an error — click it on the
canvas. A popover opens showing the node's **Input** and **Output** decoded
from protobuf to JSON, each with a copy-to-clipboard button. The input shown
is what the node actually received at execution time. Nodes that are idle or
still running do not open the popover.

For pipeline nodes the popover shows **Input Frames** and **Output Frames**
lists instead — expand a frame to decode it.

This works on the editor canvas during and after a debug run, and on the
execution detail page (`/executions/<id>`), where clicking a node opens the
same popover backed by the node's stored checkpoint and includes a
**Fork from here** button (see the forking section below).

Checkpointed payloads are not kept forever: snapshots are evicted by a
30-day TTL policy. An expired checkpoint shows "Snapshot expired" in the
popover, but the execution's event history remains available in the
**Events** tab of the detail page.

## Open the execution detail page

Click **Executions** in the header navigation to open the executions list —
a table with **Status**, **Started**, **Duration**, **Flow**, and
**Execution** columns. Click a row to open that execution's detail page at
`/executions/<id>`.

The detail page shows, top to bottom:

- **A status header** — the execution's status (Queued, Running, Debug
  paused, Completed, Failed, …) plus started/updated/completed timestamps
  and duration.
- **A read-only canvas replay** — the flow as it executed, with replay
  controls (play/pause, step, speed) and a timeline scrubber. Dragging the
  scrubber replays node states up to any point in the event history.
- **A detail tab strip** with six tabs:
  - **Timeline** — the event sequence for scrubbing.
  - **Events** — the full paginated event log, filterable by node and by
    event type.
  - **Checkpoints** — one row per node checkpoint with step number, node
    name, checkpoint ID, and creation time. Clicking a row opens the
    payload popover for that checkpoint; each row also has a
    **Fork from here** button.
  - **Pauses** — pause/resume history for the run.
  - **Branches** — branch activity for the run.
  - **Output** — the terminal node's result.

If the execution was itself forked from another execution, a
**Forked from** link in the page header navigates to the parent; executions
that have forks show a fork-descendants section linking to each child.

## Fork a debug session from a checkpoint

On the execution detail page, open the **Checkpoints** tab (or click an
executed node to open its payload popover) and click **Fork from here**.
This creates a debug session in FORK mode and navigates to
`/debug/<session-id>` — a dedicated page for re-executing the flow from
that checkpoint.

The debug session page shows:

- **A header** with the session ID, a mode pill (LIVE, REPLAY, or FORK),
  and a fork button.
- **The session canvas** with a step toolbar at the bottom-center:
  **Step Back** (keyboard `,`), **Step Forward** (keyboard `.`), and
  **Run to End** (which becomes **Stop** while running).
- **An Inspector panel** on the right showing the selected node's
  checkpointed output, plus the same six detail tabs as the execution
  detail page.

To change state before re-executing, select a node and click **Modify…** in
the Inspector. The dialog replaces one **top-level key** of the
checkpointed output with a new JSON value — top-level key replacement, not
a deep merge. Two values are rejected: a literal `null` (use **Clear** to
remove an override key instead) and values over 1&nbsp;MB. Applied overrides
take effect when you fork and step forward; the Step Forward button becomes
**Apply N override(s) and Fork** when overrides are pending.

The same promotion happens in a live debug session in the editor: if you
apply overrides while paused and then click **Step**, a confirmation dialog
asks before forking — there are no silent forks. Confirming creates the
fork and navigates to its `/debug/<session-id>` page.

Forking depends on the stored checkpoint. After the 30-day checkpoint TTL,
step, modify, and fork are disabled with the tooltip "Checkpoint expired —
fork unavailable".

## Related pages

- [Execution model](../concepts/execution-model.md) — unary vs pipeline
  execution, executions, and durability.
- [Run your first flow](../getting-started/first-flow.md) — build and run
  the flow you debug here.
- [Manage secrets in a flow](./manage-secrets.md) — fix the
  unregistered-secrets warning shown in the Run Graph dialog.
- [Flow configs](./flow-configs.md) — the **Config profile** selector in
  the Run Graph dialog.
