{"record":{"id":"059b5e420f341de9","repo":"paperclipai/paperclip","slug":"opencode-run-attach-busy","errorCode":"opencode_run_attach_busy","errorMessage":"opencode_run_attach_busy","messagePattern":"opencode_run_attach_busy","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts","lineNumber":508,"sourceCode":"          provider: input.model.split(\"/\", 1)[0],\n          opencodeVersion: input.runtime.version,\n        },\n      },\n      { itemId: `${input.providerSessionId}:model` },\n    );\n  }\n\n  ids() {\n    return {\n      driverSessionId: this.#providerSessionId,\n      providerSessionId: this.#providerSessionId,\n      displayId: this.#providerSessionId,\n    };\n  }\n\n  attachRun(input: { runId: string }): void {\n    if (this.#activeTurnId !== null)\n      throw new Error(\"opencode_run_attach_busy\");\n    if (!input.runId) throw new Error(\"opencode_run_attach_invalid\");\n    this.#runId = input.runId;\n    this.#result = null;\n    this.#resultFingerprint = null;\n    this.#resultCallId = null;\n    this.#resultTurnId = null;\n    this.#semanticResultTextBoundary = null;\n    this.#semanticResultProviderMessageId = null;\n    this.#lastNonTerminalToolSourceSeq = 0;\n    this.#completedTextPartIds.clear();\n    this.#completedReasoningPartIds.clear();\n    this.#completedTextParts.length = 0;\n    this.#terminalTurns.clear();\n    this.#sendFullContext = false;\n    this.#emit(\"run.attached\", { runId: input.runId, sameSession: true });\n  }\n\n  events(): AsyncIterable<PrpEvent> {","sourceCodeStart":490,"sourceCodeEnd":526,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts#L490-L526","documentation":"attachRun binds a new runId to an existing driver session and resets result bookkeeping. It is a synchronous, single-tenant operation: it throws opencode_run_attach_busy if a turn is still active on the session (#activeTurnId !== null), preventing two runs from interleaving on one OpenCode session.","triggerScenarios":"Calling attachRun while the previous run's turn is still in flight (stream not drained, result not consumed), or attaching a second run concurrently to the same driver instance.","commonSituations":"Runner restart logic reattaching before the prior run finished, missing await on the previous run promise, retry handlers attaching immediately after a failure without awaiting turn teardown, queue code reusing one driver for parallel tasks.","solutions":["Await completion of the active turn (consume the run result / stream end) before calling attachRun.","Use a fresh driver session for the new run instead of reattaching to a busy one.","Serialize attachRun calls through a mutex/queue per session.","If the previous turn is wedged, abort/cancel it so #activeTurnId clears, then retry attachRun."],"exampleFix":"// before\ndriver.attachRun({ runId: nextRunId }); // previous turn still active -> throws\n// after\nawait driver.waitForTurnCompletion(); // or await previousRun.result\ndriver.attachRun({ runId: nextRunId });","handlingStrategy":"retry","validationCode":"if (driver.activeTurnId !== null && driver.activeTurnId !== undefined) await driver.waitForIdle();\ndriver.attachRun({ runId });","typeGuard":"const canAttach = (d: { activeTurnId: string | null }): boolean => d.activeTurnId === null;","tryCatchPattern":"try { driver.attachRun({ runId }); } catch (e) { if ((e as Error).message === 'opencode_run_attach_busy') { await backoff(); await driver.waitForIdle(); driver.attachRun({ runId }); } else throw e; }","preventionTips":["Always await the previous run's result/stream end before reattaching","Never share one driver instance across concurrent runs; use one session per run","Cancel/abort wedged turns so state clears","Route attachRun through a per-session queue or mutex"],"tags":["opencode","concurrency","session","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}