{"record":{"id":"85e9faeba0eb0932","repo":"paperclipai/paperclip","slug":"native-runner-warm-attachment-not-quiescent","errorCode":"native_runner_warm_attachment_not_quiescent","errorMessage":"native_runner_warm_attachment_not_quiescent: ${JSON.stringify(lastBlockers)}","messagePattern":"native_runner_warm_attachment_not_quiescent: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/live/runnerd-codex-transport.ts","lineNumber":3556,"sourceCode":"        {\n          quiesceForWarmAttach: true,\n        },\n        deadline,\n      );\n      lastBlockers = snapshot.warmAttachBlockers;\n      if (snapshot.warmAttachReady === true) {\n        consecutiveReadyProbes += 1;\n        // A second barrier prevents a provider frame emitted immediately after\n        // its terminal notification from racing the authority rotation. Each\n        // snapshot wakes runnerd, polls the provider, and drains the preceding\n        // durable event prefix before the next probe.\n        if (consecutiveReadyProbes >= 2) return;\n      } else {\n        consecutiveReadyProbes = 0;\n      }\n      await new Promise<void>((resolveWait) => setTimeout(resolveWait, 25));\n    }\n    throw new Error(\n      `native_runner_warm_attachment_not_quiescent: ${JSON.stringify(lastBlockers)}`,\n    );\n  }\n\n  async #awaitWarmRunnerConnection(deadline: number): Promise<void> {\n    const core = this.#core;\n    if (core === null) throw new Error(\"native_runner_authority_unavailable\");\n    let reportedReconnectWait = false;\n    while (Date.now() < deadline) {\n      this.#throwIfFailed();\n      const connectionCount = core.activeRunnerConnectionCount();\n      if (connectionCount === 1) {\n        if (reportedReconnectWait) {\n          this.#diagnostic(\n            \"warm runner re-authenticated before authority rotation\",\n          );\n        }\n        return;","sourceCodeStart":3538,"sourceCodeEnd":3574,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/live/runnerd-codex-transport.ts#L3538-L3574","documentation":"Before rotating runner authority, the transport waits until the warm native runner's state is quiescent, polling blockers every 25ms and requiring 2 consecutive ready probes. If quiescence is never reached, it throws with a JSON dump of the last observed blockers so you can see exactly which state (e.g. in-flight turn, pending command) prevented the transition.","triggerScenarios":"Calling the warm-attachment/authority-rotation path while the runner still reports blocking state (active work, pending commands, non-idle turn) when the internal deadline expires.","commonSituations":"A long-running turn still executing when rotation is attempted; a hung runner that never drains its pending work; debugging output showing blockers like active turn IDs or queued commands in the JSON payload.","solutions":["Inspect the JSON blockers in the message to identify which runner state is stuck","Wait for or cancel the in-flight turn/run before attempting authority rotation","Restart the runner process if it is hung and never reaches quiescence","Increase the quiescence wait window if legitimate work simply needs more time"],"exampleFix":"// before\nawait transport.rotateAuthority();\n// after\ntry {\n  await transport.rotateAuthority();\n} catch (e) {\n  if (String(e.message).startsWith('native_runner_warm_attachment_not_quiescent')) {\n    const blockers = JSON.parse(e.message.split(': ')[1]);\n    logger.warn('rotation deferred, blockers:', blockers);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"const blockers = transport.getWarmAttachmentBlockers?.();\nconst ready = blockers && Object.keys(blockers).length === 0;\nif (!ready) await waitForQuiescence(transport);","typeGuard":null,"tryCatchPattern":"try {\n  await transport.rotateAuthority();\n} catch (e) {\n  if (String(e.message).startsWith('native_runner_warm_attachment_not_quiescent')) {\n    const blockers = JSON.parse(e.message.slice(e.message.indexOf(':') + 2));\n    await drainBlockers(blockers);\n    await transport.rotateAuthority();\n  } else throw e;\n}","preventionTips":["Only rotate authority when no turn/run is in flight","Cancel or await pending work before triggering warm attachment","Log runner quiescence state continuously so blockers are visible before rotation"],"tags":["codex","native-runner","warm-attachment","quiescence"],"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-14T00:17:10.932Z"}