{"record":{"id":"c493e457a1b266ed","repo":"coleam00/Archon","slug":"cannot-adopt-run-options-adoptrunid-this-con","errorCode":null,"errorMessage":"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.","messagePattern":"Cannot adopt run '(.+?)': this conversation already continues run '(.+?)' \\((.+?)\\)\\. Resume or abandon that run first, or declare the adoption from a conversation with no open run\\.","errorType":"exception","errorClass":"WorkflowAdoptionError","httpStatus":null,"severity":"error","filePath":"packages/core/src/orchestrator/orchestrator-agent.ts","lineNumber":872,"sourceCode":"  // It does NOT mirror the other refusal exit below — an explicit resume naming a run\n  // with no `working_path` is now preempted by the gate instead of reaching that check.\n  // That is a behaviour change and it is deliberate. Every row-creation site records a\n  // real `working_path`, so a NULL one means a row predating the column; reaching the\n  // gate with a violation to defer additionally needs that ancient run's workflow to\n  // have since gained a required input, and someone to resume it explicitly. (The gate\n  // judges the CURRENT YAML, not the row's vintage, so that combination is improbable\n  // rather than impossible.) Both exits refuse at zero cost, so which message wins is a\n  // wording question, not a correctness one.\n  const willContinueExistingRun =\n    Boolean(resumableRun?.working_path) &&\n    (resumableRun?.status === 'paused' || resumableRun?.id === options?.resumeRunId);\n\n  // Adoption and continuation are mutually exclusive: both decide where the run\n  // executes and which estate it inherits, and every continuation path below forwards\n  // only the resume context — an adopted id would be validated above and then silently\n  // dropped. Refuse the combination up front, mirroring the CLI's adopt/resume guard.\n  if (options?.adoptRunId !== undefined && willContinueExistingRun && resumableRun) {\n    throw new WorkflowAdoptionError(\n      `Cannot adopt run '${options.adoptRunId}': this conversation already continues ` +\n        `run '${resumableRun.id}' (${resumableRun.status}). Resume or abandon that run ` +\n        'first, or declare the adoption from a conversation with no open run.'\n    );\n  }\n\n  // ── Executable source ───────────────────────────────────────────────────────\n  //\n  // AFTER resume detection, on purpose. A continuation must execute the source its run\n  // already froze; capturing here would freeze current bytes, re-resolve the graph from\n  // them, and then hand the executor a run whose recorded capture supplies the commands\n  // and scripts — a graph from one moment against resources from another. Capturing a\n  // resume also leaves a staging directory nothing adopts.\n  //\n  // For a fresh run: freeze, then re-resolve the workflow FROM the frozen copy, so the\n  // definition executed and the resources beside it are one consistent set of bytes.\n  const runCwd = conversation.cwd ?? codebase.default_cwd;\n  // `preparedSource` is the outer binding the resume branch reads (always undefined","sourceCodeStart":854,"sourceCodeEnd":890,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/core/src/orchestrator/orchestrator-agent.ts#L854-L890","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Resume or abandon the conversation's existing resumable run first, then retry the adoption.","Remove adoptRunId and let the dispatch continue the existing run.","Start the adoption from a different conversation (or a new one) that has no open run."],"exampleFix":"// before\nawait dispatchOrchestratorWorkflow({ conversationId, adoptRunId: 'run-b' }); // conversation continues 'run-a'\n// after\nawait resumeOrAbandonRun('run-a');\nawait dispatchOrchestratorWorkflow({ conversationId, adoptRunId: 'run-b' });","handlingStrategy":"validation","validationCode":"const open = await getResumableRunForConversation(conversationId);\nif (adoptRunId && open) throw new Error(`Conversation already continues ${open.id}; resolve it before adopting`);","typeGuard":null,"tryCatchPattern":"try {\n  await dispatchOrchestratorWorkflow({ conversationId, adoptRunId });\n} catch (e) {\n  if (e instanceof WorkflowAdoptionError && e.message.includes('already continues run')) {\n    await resumeOrAbandonExistingRun(conversationId);\n    await dispatchOrchestratorWorkflow({ conversationId, adoptRunId });\n  } else throw e;\n}","preventionTips":["Never set adoptRunId on dispatches into a conversation with an open run.","Check conversation run state before sending adopt-style commands.","Prefer resume for continuing the same conversation's run; use adoption only from clean conversations."],"tags":["workflow","adoption","resume","state-conflict"],"backgroundTag":"conflicting-run-state","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}