Skip to main content

The Execution Status Model

Every workflow execution moves through a small, well-defined set of statuses. The model is worth studying because two of its distinctions — who can set a status, and transient versus permanent failure — encode the platform's whole stance on staying honest about what the engine is doing.

The statuses

workflow_execution_status_enum defines six:

StatusMeaningSet byRetryable
queuedcreated, webhook not yet dispatchedcore, at creationno
runningwebhook dispatched; engine executingcore, after dispatchno
completedsuccess; result handled, workspace advancedcore, after result handlerno
failed_transientexternal/transient failurecore (on /terminate), reconciler, or operatoryes
failed_permanentplatform-side failurecore (dispatch failure or handler throw)no
cancelledreserved for future useno

Transient vs. permanent — the key distinction

The two failure states aren't severity levels; they're diagnoses. failed_transient means the problem is outside the platform — an external service error, a crash, a guardrail self-termination, a missed callback, an operator decision. The snapshots are valid, so a retry might succeed. failed_permanent means the problem is platform-side — the webhook couldn't be dispatched, or the plugin's result handler threw — so retrying with the same snapshots would fail identically. Only failed_transient is retryable, and a retry deliberately replays the original snapshots rather than re-resolving config.

Who sets a terminal state, and why it matters

Notice that three actors can drive an execution to failed_transient: the engine (via the /terminate callback), an operator (manual termination), and the reconciler (catching stale runs). This is the visible face of the platform's Truthfulness Invariant: it must never mark an execution terminal while the engine may still be running. It's also why the reconciler only ever produces failed_transient and never completed — a genuine completion requires the workflow's result payload, which arrives only via the /complete callback, so the platform cannot fabricate success on the engine's behalf. The status model, in other words, is designed so the platform's record can be behind the engine's reality but never ahead of it.