coleam00/Archon · error · Error

Detached workflow owner has no resolved run ID

Error message

Detached workflow owner has no resolved run ID

What it means

In detached mode, the owner process must have a run ID to start the run-control server; `ownedRunId` comes from `resumable?.id ?? detachedPreCreatedRun?.id`. If the process is the detached owner but neither source yielded an ID, the CLI throws to avoid starting an uncontrolled detached run.

Source

Thrown at packages/cli/src/commands/workflow.ts:2810

  //
  // Guard rails (#1123): a signal must only ever fail THE run this process is
  // driving, and only while that run is still 'running'. The run id is learned
  // from the resumable lookup (resume path), the row a detached parent handed
  // this child (#2872), or the workflow_started emitter event (fresh runs, see
  // the subscription below) — never from a
  // conversation-wide "active run" query, which can match a run driven by
  // another process (children share parent_conversation_id). When the run has
  // already transitioned elsewhere — paused at a gate, completed, cancelled —
  // the handler leaves it alone; see "No Autonomous Lifecycle Mutation Across
  // Process Boundaries" in CLAUDE.md. The handlers themselves are removed in
  // the finally below once executeWorkflow returns, so a late signal can never
  // touch a settled run (and repeated workflowRunCommand calls in one process
  // don't stack handlers).
  let ownedRunId: string | undefined = resumable?.id ?? detachedPreCreatedRun?.id;
  let detachedRunControl: Awaited<ReturnType<typeof startDetachedRunControlServer>> | undefined;
  if (detachedProcessOwner) {
    if (ownedRunId === undefined) {
      throw new Error('Detached workflow owner has no resolved run ID');
    }
    detachedRunControl = await startDetachedRunControlServer(ownedRunId);
  }
  let terminating = false;
  const cleanup = (signal: string): void => {
    if (terminating) return;
    terminating = true;
    getLog().info({ conversationId: conversation.id, signal }, 'workflow.process_terminating');
    const interruptedRunId = ownedRunId;
    (async (): Promise<void> => {
      if (!interruptedRunId) {
        // Signal before this process created/resumed a run — nothing it owns.
        // A pre-created 'pending' row is covered by the stale-pending hygiene.
        getLog().info(
          { conversationId: conversation.id, signal },
          'workflow.termination_no_owned_run'
        );
        return;

View on GitHub (pinned to 0773b97458)

Solutions

  1. Re-run the workflow command; the run should pre-create cleanly this time.
  2. Check logs preceding this throw for a swallowed run-creation/DB error.
  3. Do not combine detach flags with resume flags unless a resumable run exists (`archon workflow list`).
  4. If reproducible, file a bug — this is an invariant violation (owner process without a run record).

Example fix

// before
if (ownedRunId === undefined) {
  throw new Error('Detached workflow owner has no resolved run ID');
}
// after
if (ownedRunId === undefined) {
  throw new Error(`Detached workflow owner has no resolved run ID (workflow=${workflowName})`);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// before starting detached control, ensure a run id resolves
const ownedRunId: string | undefined = resumable?.id ?? detachedPreCreatedRun?.id;
if (detachedProcessOwner && typeof ownedRunId !== 'string') {
  throw new Error('Refusing to detach: no run record exists to own');
}

Type guard

function hasResolvedRunId(r: { id?: string } | undefined): r is { id: string } {
  return typeof r?.id === 'string' && r.id.length > 0;
}

Try / catch

try {
  detachedRunControl = await startDetachedRunControlServer(ownedRunId as string);
} catch (err) {
  getLog().error({ err, ownedRunId }, 'cli.detached_control_start_failed');
  throw err;
}

Prevention

When it happens

Trigger: Detached execution is requested, but run pre-creation failed silently or resume resolution returned no run, so `ownedRunId === undefined` when `startDetachedRunControlServer` is called.

Common situations: A partial failure in run pre-creation (DB write failed upstream without surfacing); combining detach flags with resume context inconsistently through a wrapper; an interrupted first detach where the run row was never committed.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/b26e50694cc82d24. Report an issue: GitHub.