{"record":{"id":"8afb8011b0d35269","repo":"paperclipai/paperclip","slug":"native-runner-prp-run-rotation-unavailable","errorCode":null,"errorMessage":"native_runner_prp_run_rotation_unavailable","messagePattern":"native_runner_prp_run_rotation_unavailable","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/live/runnerd-codex-transport.ts","lineNumber":3612,"sourceCode":"        this.#failureSignal,\n      ]);\n    }\n    throw new Error(\n      `provider_transport_failed: warm runner did not re-authenticate within ${this.options.runnerReconnectGraceMs ?? 5_000}ms`,\n    );\n  }\n\n  async attachRun(input: {\n    runId: string;\n    turnId: string;\n    itemId: string;\n  }): Promise<void> {\n    if (this.#pendingWarmRecoveryCompletion !== null) {\n      throw new Error(\"native_runner_warm_transition_completion_pending\");\n    }\n    const core = this.#core;\n    if (!core || !this.#startupComplete) {\n      throw new Error(\"native_runner_prp_run_rotation_unavailable\");\n    }\n    await this.#awaitWarmRunAttachmentReady();\n    const prior = core.store.state.identity;\n    const desired: DurableRecoveryIdentity = {\n      ...prior,\n      runId: input.runId,\n      turnId: input.turnId,\n      itemId: input.itemId,\n    };\n    const registration = this.options.controlPlaneRegistration\n      ? await this.options.controlPlaneRegistration(core, desired)\n      : null;\n    const previousRelease = this.#controlPlaneRelease;\n    let previousReleased = false;\n    let activationStarted = false;\n    try {\n      const connection: RunnerProcessConnection =\n        registration?.connection ??","sourceCodeStart":3594,"sourceCodeEnd":3630,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/live/runnerd-codex-transport.ts#L3594-L3630","documentation":"attachRun requires both a live runner core and a completed startup sequence. If either is missing (core null or #startupComplete false), the run-rotation machinery is unavailable and this error is thrown.","triggerScenarios":"Calling attachRun before the transport finished its startup handshake, or after the core was torn down/failure left it unusable.","commonSituations":"Calling attachRun immediately after constructing the transport without awaiting startup; startup failed earlier (e.g. runner never came up); attach attempted after stop().","solutions":["Await the transport's startup/ready promise before calling attachRun","Check startup diagnostics to find why startup never completed","Restart the transport if the core is gone","Add a readiness check in calling code before attach"],"exampleFix":"// before\nconst transport = new RunnerdCodexTransport(...);\nawait transport.attachRun(input);\n// after\nconst transport = new RunnerdCodexTransport(...);\nawait transport.whenReady();\nawait transport.attachRun(input);","handlingStrategy":"type-guard","validationCode":"if (!transport.isReady?.()) throw new Error('transport not ready: start transport before attachRun');","typeGuard":"function isTransportReady(t) {\n  return typeof t.isReady === 'function' && t.isReady() === true;\n}","tryCatchPattern":"try {\n  await transport.attachRun(input);\n} catch (e) {\n  if (e.message === 'native_runner_prp_run_rotation_unavailable') {\n    await transport.whenReady();\n    await transport.attachRun(input);\n  } else throw e;\n}","preventionTips":["Await the transport's ready/startup promise before any attach","Verify startup succeeded (check startupComplete or equivalent) before use","Do not reuse a stopped/failed transport instance — construct a new one"],"tags":["codex","native-runner","startup","run-rotation"],"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"}