coleam00/Archon · error
Failed to complete workflow run: ${err.message}
Error message
Failed to complete workflow run: ${err.message} What it means
completeWorkflowRun() marks a workflow run row as 'completed' inside a transaction (and inserts a workflow_completed event). This wrapper error rethrows any failure from that transaction — connection loss, constraint violation, dialect/JSON merge error, transaction abort — with the original DB message appended. It distinguishes a database-level failure from the 'no matching running row' case (error 261).
Source
Thrown at packages/core/src/db/workflows.ts:1227
: await query(
`UPDATE remote_agent_workflow_runs
SET status = 'completed', completed_at = ${dialect.now()}
WHERE id = $1 AND status = 'running'`,
[id]
);
if ((update.rowCount ?? 0) > 0) {
await insertWorkflowEvent(query, {
workflow_run_id: id,
event_type: 'workflow_completed',
data: completion,
});
}
return update;
});
} catch (error) {
const err = error as Error;
getLog().error({ err }, 'db.workflow_run_complete_failed');
throw new Error(`Failed to complete workflow run: ${err.message}`);
}
if (result.rowCount === 0) {
getLog().warn({ workflowRunId: id }, 'db.workflow_run_complete_no_match');
throw new Error(`Workflow run not found or not in running state (id: ${id})`);
}
}
/**
* Mark a run failed.
*
* Matches `pending` as well as `running`. A run can fail BEFORE it ever transitions to
* running — source capture, artifact setup, and credential resolution all happen against
* a freshly inserted `pending` row — and a `running`-only guard left those rows pending
* forever: no terminal state, no error recorded, and nothing to tell the operator the run
* is dead. Both are non-terminal states owned by this process, so failing either is the
* same decision. Terminal rows still never transition.
*/
export async function failWorkflowRun(View on GitHub (pinned to 0773b97458)
Solutions
- Inspect the appended original message (err.message) and the 'db.workflow_run_complete_failed' log for the underlying DB error
- Verify database connectivity and that the DB server was up for the duration of the run
- Ensure the metadata argument is JSON-serializable and matches the expected Record<string, unknown> shape
- Confirm the schema is up to date (migrations applied; both SQLite and PostgreSQL shapes aligned)
- Retry the completion write once the database is healthy; the run must still be in 'running' state for the update to apply
Example fix
// before
await completeWorkflowRun(id, { duration_ms: 1234 }, metadata as any);
// after
try {
await completeWorkflowRun(id, { duration_ms: 1234 }, metadata);
} catch (err) {
if (!err.message.startsWith('Workflow run not found')) {
getLog().error({ err, workflowRunId: id }, 'complete retryable db failure');
await completeWorkflowRun(id, { duration_ms: 1234 }); // retry without metadata
}
} Defensive patterns
Strategy: try-catch
Validate before calling
const run = await getWorkflowRun(id);
if (!run) throw new Error(`run ${id} does not exist`);
if (run.status !== 'running') throw new Error(`run ${id} is ${run.status}, not running`);
JSON.stringify(metadata ?? {}); // ensure metadata is serializable Type guard
function isRecord(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null && !Array.isArray(v);
} Try / catch
try {
await completeWorkflowRun(id, { duration_ms }, metadata);
} catch (err) {
if (err.message.startsWith('Workflow run not found')) {
// state issue: reconcile with current run status
} else {
// DB failure: log err.message (original cause) and retry after health check
}
} Prevention
- Confirm run status is 'running' before completing
- Keep metadata JSON-serializable and schema-conformant
- Keep schema/migrations current for the deployed binary
- Monitor 'db.workflow_run_complete_failed' logs for the underlying DB error
- Avoid calling completion from multiple code paths
When it happens
Trigger: Calling completeWorkflowRun(id, completion, metadata?) when the underlying UPDATE/INSERT transaction fails: database unreachable or dropped mid-transaction, metadata JSON serialization/dialect jsonMerge failure, workflow event insert constraint violation, or transaction deadlock/rollback.
Common situations: Postgres/SQLite restarted or connection pooled out during a long workflow; passing metadata containing values that fail JSON.stringify or violate a schema; a duplicate-key error on the workflow event insert; running against a stale database whose remote_agent_workflow_runs or events table lacks expected columns.
Related errors
- Workflow run not found or not in running state (id: ${id})
- Failed to fail workflow run: ${err.message}
- Workflow run not found or already terminal (id: ${id})
- Failed to get workflow run: ${err.message}
- Workflow run '${runId}' references codebase '${codebaseId}',
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/e2e2fbffc28bccb5.
Report an issue: GitHub.