Error handling
Orbital has two separate failure vocabularies, and confusing them is the most common source of surprise. A stage outcome describes one step. A terminal outcome describes the whole run.
Stage failure
Section titled “Stage failure”The engine writes outcome as succeeded or failed after each stage, with failure_reason empty on success. An agent harness error, exhausted output correction, or a failed script fails a stage.
A failed stage takes a matching conditioned edge. It never takes the ordinary fallback. With no failure route it holds for the operator, which is a hold, not an end. Use condition="outcome == 'failed'" to send work to a repair prompt, and read {{ context.failure_reason }} in that prompt.
A terminal’s run outcome uses success, failed or aborted. That is a different vocabulary from the stage outcome, and a failed terminal ends the run rather than holding it.
What fails a step
Section titled “What fails a step”A script fails on a timeout, a non-zero exit or a malformed final JSON line, and sets <node>.failed to true either way. Malformed agent output triggers up to two correction turns in the same session; if correction fails, the node fails. Context changes only after acceptance, so a rejected output leaves nothing behind.
Failed probe attempts retry inside the same node and record retry progress. They spend no new node visits and take no graph failure edge per attempt. A probe that keeps retrying is still inside its observation node, so inspect its diagnostic and credentials rather than the graph’s edges.
A worktree removal that would lose dirty files or unpushed work removes nothing and writes worktree.clean false with the detail in worktree.status. Route on worktree.clean and give the refusal its own terminal.
Bounded repair
Section titled “Bounded repair”repair_budget is a name beginning with a letter and containing letters, digits or underscores. repair_round is retry, exhausted or reset. Both attributes must appear together, and budget names are shared across the flattened graph, including imports.
A retry edge starts a repair round. After five unsuccessful rounds the matching exhausted edge runs once. Every retry needs an exhausted partner with the same explicit condition and budget but a different weight. Neither is eligible again until a reset edge runs; place reset on demonstrated success or a new work episode. Ordinary waiting spends no rounds.
Budget state survives resume and loop restart. Budget actions cannot appear on the fan-out or inside parallel branches; put them after the join. Graph and node visit limits remain independent, and exceeding either holds for the operator instead of routing.
Partial parallel failure
Section titled “Partial parallel failure”Successful collection of every branch enters the join. Partial failure takes a matching conditioned edge from the fan-out, or holds for the operator and names the failed branches.
How to do looping shows recovery and exhaustion in a complete graph. Troubleshooting explains how each state appears in the interface.
Inline attribute expressions on this page are syntax fragments. Use the complete attribute wrapper and the linked runnable examples as validation contexts.