paperclipai/paperclip · error
native_runner_authority_rotation_state_unavailable
native_runner_authority_rotation_state_unavailable
Error message
native_runner_authority_rotation_state_unavailable
What it means
rotateLocalAuthorityEpoch() needs a readable runner state to validate before rotating: it uses the live runner-state.json if present, else the archived copy inside the authority epoch archive. If neither file exists it throws native_runner_authority_rotation_state_unavailable — the rotation cannot proceed because there is no prior runner state to validate and archive.
Source
Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:301
priorIdentity.runnerInstanceId !== desired.runnerInstanceId ||
priorIdentity.environmentLeaseId !== desired.environmentLeaseId ||
priorIdentity.normalizedSessionId !== desired.normalizedSessionId ||
priorIdentity.runId === desired.runId
) {
throw new Error(
"PRP recovery identity does not match the durable session binding",
);
}
const runnerDirectory = resolve(root, "runner");
const runnerStatePath = resolve(runnerDirectory, "runner-state.json");
const archive = authorityArchiveDirectory(root, priorIdentity);
const archivedControlPlane = resolve(archive, "control-plane");
const archivedRunnerState = resolve(archive, "runner-state.json");
const runnerStateSource = existsSync(runnerStatePath)
? runnerStatePath
: archivedRunnerState;
if (!existsSync(runnerStateSource)) {
throw new Error("native_runner_authority_rotation_state_unavailable");
}
assertRealDirectory(runnerDirectory);
const runnerState = readRunnerState(runnerStateSource);
if (
runnerState.runnerInstanceId !== priorIdentity.runnerInstanceId ||
runnerState.environmentLeaseId !== priorIdentity.environmentLeaseId ||
runnerState.runId !== priorIdentity.runId ||
runnerState.normalizedSessionId !== priorIdentity.normalizedSessionId ||
runnerState.turnId !== priorIdentity.turnId ||
runnerState.itemId !== priorIdentity.itemId ||
runnerState.lifecycle !== "suspended"
) {
throw new Error("native_runner_authority_rotation_requires_settled_state");
}
const archivesRoot = resolve(root, "authority-epochs");
if (existsSync(archivesRoot)) {
assertRealDirectory(archivesRoot);
} else {View on GitHub (pinned to 01ad858492)
Solutions
- Confirm you are pointing at the correct state root (a misconfigured root looks identical to a missing state)
- Check for leftover quarantine or partially rotated directories (<root>.quarantine-*, authority-epochs) and restore runner-state.json from them
- If state is genuinely absent, re-initialize the runner/session instead of rotating (rotation requires prior state)
- Restore from backup of the runner state directory before resuming
Example fix
// before pnpm runner resume --state-root data/runner-state # runner-state.json deleted by cleanup // after ls data/runner-state*/ && find data -name 'runner-state.json' # restore from archive/quarantine copy: cp data/runner-state.quarantine-<uuid>/runner/runner-state.json data/runner-state/runner/runner-state.json
Defensive patterns
Strategy: fallback
Validate before calling
import { existsSync } from "node:fs";
function hasRunnerState(root: string): boolean {
return existsSync(`${root}/runner/runner-state.json`) ||
existsSync(`${root}/authority-epochs`); // archives may hold prior state
} Try / catch
try {
await transport.resume();
} catch (err) {
if (err.code === "native_runner_authority_rotation_state_unavailable") {
logger.error("no runner-state.json live or archived; re-init required");
reinitializeRunnerState();
} else throw err;
} Prevention
- Do not run cleanup jobs against live runner state directories
- Verify the state root config before resume
- After a failed rotation, reconcile from quarantine/archive copies before retrying
- Back up the runner directory before maintenance
When it happens
Trigger: #resume() triggers local rotation while both runner-state.json and the archived runner-state.json (under the authority-epochs archive's control-plane/runners layout) are missing.
Common situations: State directory partially cleaned up by an operator or cleanup job; interrupted prior rotation that moved the live file but never archived it; fresh/re-initialized state root that never had runner state; wrong state root configured.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- native_runner_control_plane_state_unsafe
- native_runner_authority_rotation_state_unsafe
- native_runner_authority_rotation_requires_settled_state
- PRP recovery identity does not match the durable session bin
- native_runner_authority_archive_conflict
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/a31234a3c5700de3.
Report an issue: GitHub.