coleam00/Archon · error
executor.backstop_triggered
executor.backstop_triggered
Error message
Workflow exited without finalizing — see logs
What it means
A safety backstop in the executor's finally block: if the workflow function exits (returns or throws) while the run is still recorded as 'running' and no terminal status write already failed, the run would remain a zombie. The backstop marks it failed with this message so terminal state always lands. It exists because of the zombie-state incident #1561; the message directs you to logs for the real cause.
Source
Thrown at packages/workflows/src/executor.ts:3237
// Return failure result instead of re-throwing
return { success: false, workflowRunId: workflowRun.id, error: err.message };
} finally {
// Release the keep-awake request FIRST — before the backstop DB calls that
// may throw — so it always pairs with the acquire above this try, on every
// exit path (success, thrown error, or backstop failure).
keepAwake.release();
// Defensive backstop: if the workflow run is still 'running' after all
// normal and exceptional code paths, flip it to 'failed' to prevent zombie
// accumulation. Guards against any future code path that exits without
// calling failWorkflowRun (e.g. a generator cleanup that exits without
// throwing). Only fires when the process stays alive long enough to run
// this finally — see #1561 for the originating zombie-state incident.
if (workflowRun && !terminalStatusWriteFailed) {
const runId = workflowRun.id;
const backstopStatus = await deps.store.getWorkflowRunStatus(runId).catch(() => null);
if (backstopStatus === 'running') {
getLog().warn({ workflowRunId: runId }, 'executor.backstop_triggered');
await requireTerminalStatusWrite(
deps.store.failWorkflowRun(runId, 'Workflow exited without finalizing — see logs'),
{ workflowRunId: runId, site: 'executor.backstop_fail_failed' }
);
}
}
}
}
View on GitHub (pinned to 0773b97458)
Solutions
- Check the executor logs for the workflowRunId to find the exception or early return that bypassed finalization.
- Fix the root cause in the workflow/node code that threw or returned without reaching finalize, then re-run the workflow.
- Reconcile the zombie run via CLI (`archon workflow resume` or cancel) if a status write raced or was lost.
- Add tests covering throw and early-return exit paths so finalize is always reached.
Example fix
// before: early return that skips finalize
if (!nodes.length) return;
// after: route through the executor's error/finalize path
if (!nodes.length) {
throw new Error('Workflow has no nodes'); // executor terminalizes the run
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await executeWorkflow(/* ... */);
} catch (err) {
// guarantee terminalization even on unexpected throws
await store.failWorkflowRun(runId, `Unhandled executor error: ${err}`);
throw err;
} Prevention
- Never add early returns inside the workflow execution function that bypass the finalize path.
- Wrap custom node handlers so unexpected throws propagate through the executor's normal failure handling.
- Monitor logs for executor.backstop_triggered — each occurrence is a finalize-path bug to fix, not just a run to restart.
- Add regression tests for throw and early-return exit paths in custom node types.
When it happens
Trigger: The executor's finally block runs with workflowRun set, terminalStatusWriteFailed false, and store.getWorkflowRunStatus(runId) === 'running' — i.e. the workflow body returned early or threw an error that bypassed the normal finalize path (executor.ts:3237), and the process stayed alive long enough for the finally to execute.
Common situations: An uncaught exception in a node handler outside normal error handling; a code change adding an early return before finalization; an abort/OOM mid-node skipping completion; custom node types that swallow control flow.
Related errors
- Cannot supersede run '${superseded.id}': it is still ${super
- Cannot execute run '${detachedPreCreatedRun.id}': it belongs
- Dry-run failed; missing stubs: ${blockingMissingStubs.join('
- result.error
- Failed to get workflow run: ${err.message}
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/8f07eb47303ca80a.
Report an issue: GitHub.