paperclipai/paperclip · error
native_adopted_runner_exited
native_adopted_runner_exited
Error message
native_adopted_runner_exited: runner exited before PRP authentication
What it means
While waiting for an adopted runner to authenticate, the wait loop polls whether the runner process is still alive. If the process has exited before PRP authentication completed, waiting longer is pointless and the durable session must be preserved for operator recovery, so the loop throws this coded error naming the exit-before-auth condition.
Source
Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:834
);
let cancelled = false;
let pollTimer: NodeJS.Timeout | undefined;
let deadlineTimer: NodeJS.Timeout | undefined;
const checkDeadline = () => {
if (Date.now() >= deadline) throw timeoutError();
};
const observe = async () => {
await input.ready?.();
while (!cancelled) {
input.throwIfFailed();
checkDeadline();
if (input.activeConnectionCount() === 1) return;
const alive = await input.isAlive();
if (cancelled) return;
input.throwIfFailed();
checkDeadline();
if (!alive) {
throw new Error(
"native_adopted_runner_exited: runner exited before PRP authentication",
);
}
if (input.activeConnectionCount() === 1) return;
await new Promise<void>((resolveWait) => {
pollTimer = setTimeout(
resolveWait,
Math.min(25, deadline - Date.now()),
);
});
}
};
try {
await Promise.race([
observe(),
input.failure,
new Promise<never>((_resolve, reject) => {
deadlineTimer = setTimeout(View on GitHub (pinned to 01ad858492)
Solutions
- Check the runner process logs/stderr to determine why it exited before authentication
- Verify the runner binary exists, is executable, and matches the expected protocol version
- Restart/re-adopt the runner process, preserving its durable session state for recovery
- Increase runnerReconnectGraceMs only if the process is being killed by a timeout race, not if it is crashing
Example fix
// before
await awaitAdoptedRunnerAuthentication({ isAlive, ... }); // throws raw exit error
// after
try {
await awaitAdoptedRunnerAuthentication({ isAlive, ... });
} catch (err) {
if ((err as Error).message.startsWith("native_adopted_runner_exited")) {
await recoverRunnerSession(); // inspect logs, restart runner, preserve durable session
} else throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!(await isAlive())) {
throw new Error("runner already dead; restart it before awaiting PRP authentication");
} Type guard
const runnerReadyForAuthWait = async (isAlive: () => Promise<boolean>) => (await isAlive()) && Number.isSafeInteger(timeoutMs) && timeoutMs > 0;
Try / catch
try {
await awaitAdoptedRunnerAuthentication({ ... });
} catch (err) {
if ((err as Error).message.startsWith("native_adopted_runner_exited")) {
await collectRunnerLogsAndRecover();
} else throw err;
} Prevention
- Verify the runner binary/version before adoption
- Capture the runner's stderr to diagnose early exits
- Use a supervisor that restarts crashed runners and preserves durable session state
When it happens
Trigger: Calling awaitAdoptedRunnerAuthentication (via #awaitAdoptedRunnerConnection) when isAlive() returns false during the polling loop — i.e., the adopted runner process died after adoption started but before it opened its single authenticated connection.
Common situations: The adopted CLI process crashed on startup (bad config, missing binary, version mismatch); the process was killed externally (OOM, supervisor); authentication hung long enough that the process was terminated; incompatible runner/protocol versions causing an immediate exit.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Failed to stop Daytona sandbox during lease release: ${forma
- provider turn ended with status ${turn.status}
- SSH env-lab fixture state exists, but the process is not run
- [opencode-local] Remote model availability probe for "${mode
- Agent identity is required
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/3d5db4973a983617.
Report an issue: GitHub.