paperclipai/paperclip · error

native_runner_warm_transition_completion_unproven

Error message

native_runner_warm_transition_completion_unproven

What it means

Thrown after a `session.snapshot` PRP command completes during warm recovery, when the snapshot fails to prove the native runner's warm transition completed. The transport checks that the resolved provider identity matches the expected driver session id and provider session id, and that `result.status` is one of `prepared`, `session_open`, or `turn_active`. Any mismatch means the warm transition cannot be confirmed.

Source

Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:5483

      const expectation = this.#checkpointProviderIdentityExpectation;
      const providerIdentity = resolveRunnerdSessionIdentity(result);
      if (
        command.type !== "session.snapshot" ||
        core.store.state.warmTransition !== undefined ||
        !recoveryIdentityMatches(
          core.store.state.identity,
          completion.identity,
        ) ||
        core.store.state.completedWarmTransition?.receipt.transitionId !==
          completion.transitionId ||
        expectation === null ||
        providerIdentity.threadId !== expectation.driverSessionId ||
        providerIdentity.sessionId !== expectation.providerSessionId ||
        !["prepared", "session_open", "turn_active"].includes(
          String(result.status),
        )
      ) {
        throw new Error("native_runner_warm_transition_completion_unproven");
      }
      this.#confirmCheckpointProviderIdentity(
        result,
        "fresh post-activation session.snapshot",
      );
      // This newly queued command completed only after runner consumed the
      // final activation ACK. Callback failure retains the completion gate;
      // retry observes a fresh snapshot, never repeats a provider turn.
      const completing = (this.#warmRecoveryCompletionInFlight ??=
        Promise.resolve().then(() =>
          this.options.onWarmTransitionRecoveryCompleted?.({
            transitionId: completion.transitionId,
          }),
        ));
      try {
        await completing;
        if (this.#pendingWarmRecoveryCompletion === completion) {
          this.#pendingWarmRecoveryCompletion = null;

View on GitHub (pinned to 01ad858492)

Solutions

  1. Re-run warm recovery from a fresh checkpoint so expectations match the current provider session identity.
  2. Verify runnerd was not restarted between checkpoint capture and recovery; if it was, cold-start instead of warm-starting.
  3. Inspect the snapshot `status` — if it is still initializing, retry after the session reaches `prepared`/`session_open`/`turn_active`.
  4. Check that `resolveRunnerdSessionIdentity` matches the snapshot shape emitted by your runnerd version.

Example fix

// before
if (providerIdentity.threadId !== expectation.driverSessionId ||
    providerIdentity.sessionId !== expectation.providerSessionId) {
  throw new Error("native_runner_warm_transition_completion_unproven");
}
// after
if (providerIdentity.threadId !== expectation.driverSessionId ||
    providerIdentity.sessionId !== expectation.providerSessionId) {
  logger.warn({ expected: expectation, got: providerIdentity }, "warm transition identity mismatch; invalidating checkpoint");
  await this.#invalidateCheckpoint();
  throw new Error("native_runner_warm_transition_completion_unproven");
}
Defensive patterns

Strategy: validation

Validate before calling

const identity = resolveRunnerdSessionIdentity(snapshot);
if (identity.threadId !== expectation.driverSessionId || identity.sessionId !== expectation.providerSessionId) {
  invalidateCheckpoint();
}

Type guard

function isWarmTransitionSnapshot(result) {
  return ["prepared", "session_open", "turn_active"].includes(result?.status);
}

Try / catch

try {
  await warmRecover(checkpoint);
} catch (err) {
  if (err.message === "native_runner_warm_transition_completion_unproven") {
    await coldStart(); // fall back to a fresh session
  } else throw err;
}

Prevention

When it happens

Trigger: Warm recovery path queues a `session.snapshot` command with a pending warm-recovery completion, then `resolveRunnerdSessionIdentity(result)` yields a threadId/sessionId that differs from `expectation.driverSessionId`/`expectation.providerSessionId`, or the snapshot `status` is outside the accepted set.

Common situations: Stale checkpoint expectations after the provider session was recreated; runnerd restarted into a fresh session so the old session IDs no longer match; snapshot taken too early (status like `idle`/`initializing`); session identity resolution parsing a differently shaped snapshot.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/f86360b88d9c90e9. Report an issue: GitHub.