coleam00/Archon · error
Cannot reject run with status '${run.status}'. Only paused r
Error message
Cannot reject run with status '${run.status}'. Only paused runs can be rejected. What it means
assertRejectable enforces that only runs in 'paused' status can be rejected. A run is rejectable only when it is parked at a human approval gate; a running, completed, failed, or cancelled run has no gate to reject. The library throws this to prevent mutating runs whose lifecycle state does not admit a rejection decision.
Source
Thrown at packages/core/src/operations/workflow-operations.ts:334
? `Workflow run ${run.id} was already ${String(approval.resolved)} and is awaiting resume.`
: 'Workflow run is paused but missing approval context.'
);
}
}
/**
* The preconditions `rejectWorkflow` enforces. Reads the same `runAttention`
* decision as `assertApprovable` but acts on one variant differently, and that
* difference is real: reject has no `nodeId` requirement — it falls back to
* `approval?.nodeId ?? 'unknown'` when writing its audit event, so a run whose gate
* metadata is unreadable (`malformed_gate`) is still legitimately rejectable. A
* well-formed context with an unrecognized `type` is NOT one of those cases — it
* throws, same as approve. Merging the two gates would either break reject or
* over-permit approve.
*/
export function assertRejectable(run: WorkflowRun): ApprovalContext | undefined {
if (run.status !== 'paused') {
throw new Error(
`Cannot reject run with status '${run.status}'. Only paused runs can be rejected.`
);
}
const rawApproval = run.metadata.approval;
const approval: ApprovalContext | undefined = isApprovalContext(rawApproval)
? rawApproval
: undefined;
const attention = runAttention(run);
switch (attention?.kind) {
case 'blocked_on_child':
// Same redirect as assertApprovable: the parent's pause is not a rejectable
// gate — cancelling the parent here would silently orphan the still-paused
// child run. Reject the child (its own gate) or abandon the parent (which
// cascade-cancels the subtree) instead.
throw new Error(
`Run ${run.id} is paused waiting on sub-run ${attention.childRunId} ` +
`('workflow:' node '${attention.nodeId}'). Reject the child run instead` +
`: /workflow reject ${attention.childRunId}` +View on GitHub (pinned to 0773b97458)
Solutions
- Check the run's status first (getRun/workflow status command) and only issue reject when status === 'paused'.
- If the run already completed, there is nothing to reject — abandon it if you want it discarded, or start a new run.
- If the run is stuck 'running' but should be stopped, cancel or abandon it instead of rejecting.
- Re-fetch the run if your local view is stale; the gate may have resumed between listing and rejecting.
Example fix
// before
await workflowRejectCommand({ runId });
// after
const run = await getRun(runId);
if (run.status === 'paused') {
await workflowRejectCommand({ runId });
} else {
console.log(`Run is ${run.status}; nothing to reject.`);
} Defensive patterns
Strategy: validation
Validate before calling
const run = await getRun(runId);
if (run.status !== 'paused') throw new Error(`Run ${runId} is ${run.status}, not rejectable`); Type guard
function isRejectable(run: WorkflowRun): boolean { return run.status === 'paused'; } Try / catch
try { await workflowRejectCommand({ runId }); }
catch (e) {
if ((e as Error).message.startsWith("Cannot reject run with status")) {
console.warn(`Skip reject: run not paused (${(e as Error).message})`);
} else throw e;
} Prevention
- Always fetch fresh run status immediately before issuing reject.
- Only surface reject actions in UI when run.status === 'paused'.
- Treat pause->resume races by re-checking status after any failed reject.
When it happens
Trigger: Calling workflowRejectCommand (or the approval flow calling assertRejectable) on a run whose status is 'running', 'completed', 'failed', or 'cancelled' — e.g. rejecting a run that already finished, or a run that is still executing.
Common situations: A developer or operator runs '/workflow reject <id>' after the run already resumed and completed; a stale UI or chat message references a run ID that has since moved past its approval gate; a race where the run resumed between listing paused runs and issuing the reject.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Run ${run.id} is paused waiting on sub-run ${attention.child
- unreadableGateMessage(run, attention, approval) — one of: "R
- Workflow run ${run.id} was already ${String(approval.resolve
- Cannot resume run with status '${run.status}'. Only failed o
- Cannot abandon run with status '${run.status}'. Only running
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/004a96f43ac444cb.
Report an issue: GitHub.