{"record":{"id":"414af5ac6d0ae249","repo":"paperclipai/paperclip","slug":"prp-provider-thread-is-already-started","errorCode":null,"errorMessage":"PRP provider thread is already started","messagePattern":"PRP provider thread is already started","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/live/runnerd-codex-transport.ts","lineNumber":4285,"sourceCode":"    } finally {\n      await this.#core?.stop();\n      this.#controlPlaneCheckpoint = null;\n      this.#controlPlaneRelease = null;\n    }\n    if (suspensionRequired && !runnerSettled) {\n      throw new NativeSessionCloseUnrecoverableError();\n    }\n    if (this.#ownsRoot && !adoptedRunner) {\n      rmSync(this.#root, { recursive: true, force: true });\n    }\n    this.#publish();\n  }\n\n  async #start(\n    params: Record<string, unknown>,\n  ): Promise<Record<string, unknown>> {\n    if (this.#core !== null)\n      throw new Error(\"PRP provider thread is already started\");\n    if (this.options.adoptExistingRunner) {\n      // A crash can precede the first driver checkpoint even though runnerd\n      // already opened the provider. Exact process adoption must reuse that\n      // authority instead of enqueueing another run.prepare/session.open pair.\n      await this.#resume();\n      return this.#openedThreadResponse(params);\n    }\n    const token = randomUUID().replaceAll(\"-\", \"\");\n    const identity = this.options.prpIdentity ?? {\n      runnerInstanceId: `runner_lab_${token}`,\n      environmentLeaseId: `lease_lab_${token}`,\n      runId: `run_lab_${token}`,\n      normalizedSessionId: `session_lab_${token}`,\n      turnId: `turn_lab_${token}`,\n      itemId: `item_lab_${token}`,\n    };\n    const runnerBinaryPath =\n      this.options.runnerBinary ?? defaultCapabilityRunnerdBinary();","sourceCodeStart":4267,"sourceCodeEnd":4303,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/paperclip-runner/src/live/runnerd-codex-transport.ts#L4267-L4303","documentation":"Double-start guard on the runnerd Codex transport's #start: the provider thread is single-instance — #core must be null when starting — so a second start request while a provider thread is already running throws this sentinel instead of spawning a duplicate core. It fires on re-entrant or duplicate start RPCs (e.g. a start retried after a timeout that actually succeeded).","triggerScenarios":"Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:4285 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the start result/state before retrying a start that may have already succeeded (idempotent start handling).","Stop the existing provider thread (close) before starting a new one if a restart is intended.","Trace the duplicate start RPC to its source and deduplicate at the control-plane caller."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}