{"record":{"id":"281e66cf050f5f5c","repo":"paperclipai/paperclip","slug":"native-runner-warm-transition-snapshot-mismatch","errorCode":null,"errorMessage":"native_runner_warm_transition_snapshot_mismatch","messagePattern":"native_runner_warm_transition_snapshot_mismatch","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/live/runnerd-codex-transport.ts","lineNumber":4671,"sourceCode":"          this.options.warmTransitionRegistrationMode !== \"routed_connect\") ||\n        this.options.adoptExistingRunner !== undefined\n      ) {\n        throw new Error(\n          \"native_runner_warm_transition_requires_exact_owned_endpoint\",\n        );\n      }\n      const artifact = approvedRunnerArtifact(\n        this.options.runnerBinary ?? defaultCapabilityRunnerdBinary(),\n      );\n      const proof = inspectWarmRunTransition({\n        controlPlaneState,\n        runnerState: candidateRunnerState,\n        expectedNewIdentity: desiredIdentity,\n        expectedRunnerVersion: artifact.version,\n        expectedRunnerDigest: artifact.digest,\n      });\n      if (!proof)\n        throw new Error(\"native_runner_warm_transition_snapshot_mismatch\");\n      const receipt = proof.receipt;\n      const connection = receipt.connection;\n      const endpoint =\n        typeof connection.connectUrl === \"string\"\n          ? new URL(connection.connectUrl)\n          : null;\n      if (\n        connection.mode !== \"connect\" ||\n        endpoint === null ||\n        endpoint.search ||\n        endpoint.hash ||\n        endpoint.username ||\n        endpoint.password ||\n        (!this.options.controlPlaneRegistration &&\n          (endpoint.protocol !== \"ws:\" ||\n            endpoint.hostname !== \"127.0.0.1\" ||\n            endpoint.pathname !== \"/durableRecovery/connect\" ||\n            !endpoint.port))","sourceCodeStart":4653,"sourceCodeEnd":4689,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/live/runnerd-codex-transport.ts#L4653-L4689","documentation":"Thrown when the warm-transition snapshot proof cannot be produced: proofWasmRunnerSnapshot returns no proof for the candidate runner state given the expected new identity, runner version, and runner digest. This means the on-disk/remote snapshot does not match what the transition expects to own.","triggerScenarios":"candidateRunnerState is stale or from a different runner binary version/digest than the approved artifact; desiredIdentity (prpIdentity) does not match the snapshot's identity; the runner state file was regenerated or overwritten between capture and proof.","commonSituations":"Runner binary upgraded between snapshot capture and warm transition; mixed-version fleet where the controller expects one digest but the runner wrote another; resuming a snapshot captured for a different turn/session.","solutions":["Re-capture the candidate runner state with the currently approved runner binary","Verify the runner binary digest/version matches the approved artifact (approvedRunnerArtifact)","Ensure prpIdentity passed to the transition matches the snapshot's session/turn/item identity","Re-run the warm transition after the underlying turn state has been re-synced"],"exampleFix":"// before\nconst artifact = approvedRunnerArtifact(localRunnerBinaryPath); // stale binary\nconst proof = proofWasmRunnerSnapshot({ runnerState: candidateRunnerState, expectedRunnerDigest: artifact.digest });\n// after\nconst artifact = approvedRunnerArtifact(this.options.runnerBinary ?? defaultCapabilityRunnerdBinary());\nconst freshState = await readRunnerState(root); // re-read state matching the approved binary\nconst proof = proofWasmRunnerSnapshot({ runnerState: freshState, expectedRunnerDigest: artifact.digest, expectedRunnerVersion: artifact.version });","handlingStrategy":"retry","validationCode":"const artifact = approvedRunnerArtifact(runnerBinary);\nif (candidateRunnerState.runnerVersion !== artifact.version ||\n    candidateRunnerState.runnerDigest !== artifact.digest) {\n  throw new Error(\"runner state does not match approved artifact; re-capture before transition\");\n}","typeGuard":"null","tryCatchPattern":"try {\n  await transport.beginWarmTransition();\n} catch (err) {\n  if (err instanceof Error && err.message === \"native_runner_warm_transition_snapshot_mismatch\") {\n    await recaptureRunnerState();\n    await transport.beginWarmTransition();\n  } else throw err;\n}","preventionTips":["Re-capture runner state immediately before warm transitions","Pin runner binary versions across controller and runners","Verify identity fields of the snapshot match prpIdentity before transitioning"],"tags":["snapshot","integrity","version-mismatch"],"backgroundTag":"checksum-mismatch","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"}