coleam00/Archon · error · WorkflowAdoptionError

Cannot adopt run '${options.adoptRunId}': this conversation

Error message

Cannot adopt run '${options.adoptRunId}': this conversation already continues run '${resumableRun.id}' (${resumableRun.status}). Resume or abandon that run first, or declare the adoption from a conversation with no open run.

What it means

WorkflowAdoptionError thrown when a dispatch both requests adoption of a run (adoptRunId) and would naturally continue an existing resumable run in the same conversation. Adoption and continuation are mutually exclusive — both decide where the run executes and which estate it inherits — so the combination is rejected up front instead of silently dropping the adopted id.

Source

Thrown at packages/core/src/orchestrator/orchestrator-agent.ts:872

  // It does NOT mirror the other refusal exit below — an explicit resume naming a run
  // with no `working_path` is now preempted by the gate instead of reaching that check.
  // That is a behaviour change and it is deliberate. Every row-creation site records a
  // real `working_path`, so a NULL one means a row predating the column; reaching the
  // gate with a violation to defer additionally needs that ancient run's workflow to
  // have since gained a required input, and someone to resume it explicitly. (The gate
  // judges the CURRENT YAML, not the row's vintage, so that combination is improbable
  // rather than impossible.) Both exits refuse at zero cost, so which message wins is a
  // wording question, not a correctness one.
  const willContinueExistingRun =
    Boolean(resumableRun?.working_path) &&
    (resumableRun?.status === 'paused' || resumableRun?.id === options?.resumeRunId);

  // Adoption and continuation are mutually exclusive: both decide where the run
  // executes and which estate it inherits, and every continuation path below forwards
  // only the resume context — an adopted id would be validated above and then silently
  // dropped. Refuse the combination up front, mirroring the CLI's adopt/resume guard.
  if (options?.adoptRunId !== undefined && willContinueExistingRun && resumableRun) {
    throw new WorkflowAdoptionError(
      `Cannot adopt run '${options.adoptRunId}': this conversation already continues ` +
        `run '${resumableRun.id}' (${resumableRun.status}). Resume or abandon that run ` +
        'first, or declare the adoption from a conversation with no open run.'
    );
  }

  // ── Executable source ───────────────────────────────────────────────────────
  //
  // AFTER resume detection, on purpose. A continuation must execute the source its run
  // already froze; capturing here would freeze current bytes, re-resolve the graph from
  // them, and then hand the executor a run whose recorded capture supplies the commands
  // and scripts — a graph from one moment against resources from another. Capturing a
  // resume also leaves a staging directory nothing adopts.
  //
  // For a fresh run: freeze, then re-resolve the workflow FROM the frozen copy, so the
  // definition executed and the resources beside it are one consistent set of bytes.
  const runCwd = conversation.cwd ?? codebase.default_cwd;
  // `preparedSource` is the outer binding the resume branch reads (always undefined

View on GitHub (pinned to 0773b97458)

Solutions

  1. Resume or abandon the conversation's existing resumable run first, then retry the adoption.
  2. Remove adoptRunId and let the dispatch continue the existing run.
  3. Start the adoption from a different conversation (or a new one) that has no open run.

Example fix

// before
await dispatchOrchestratorWorkflow({ conversationId, adoptRunId: 'run-b' }); // conversation continues 'run-a'
// after
await resumeOrAbandonRun('run-a');
await dispatchOrchestratorWorkflow({ conversationId, adoptRunId: 'run-b' });
Defensive patterns

Strategy: validation

Validate before calling

const open = await getResumableRunForConversation(conversationId);
if (adoptRunId && open) throw new Error(`Conversation already continues ${open.id}; resolve it before adopting`);

Try / catch

try {
  await dispatchOrchestratorWorkflow({ conversationId, adoptRunId });
} catch (e) {
  if (e instanceof WorkflowAdoptionError && e.message.includes('already continues run')) {
    await resumeOrAbandonExistingRun(conversationId);
    await dispatchOrchestratorWorkflow({ conversationId, adoptRunId });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling dispatchOrchestratorWorkflow with options.adoptRunId in a conversation whose state already yields a resumable run (willContinueExistingRun && resumableRun), e.g. sending a follow-up message that says 'adopt run X' while the conversation is mid-continuation of run Y.

Common situations: A user pastes an adopt command into a conversation that already has an open run; an automation sets adoptRunId unconditionally while the session state also carries a resumable run; mixing the CLI's resume flow with an adopt flag.

Related errors


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