paperclipai/paperclip · error
native_runner_warm_attachment_ambiguous: expected one authen
Error message
native_runner_warm_attachment_ambiguous: expected one authenticated runner, found ${connectionCount} What it means
During warm attachment exactly one authenticated runner connection is expected. If the core reports more than one authenticated runner connection, the transport cannot tell which one holds authority and throws, embedding the observed connection count.
Source
Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:3577
}
async #awaitWarmRunnerConnection(deadline: number): Promise<void> {
const core = this.#core;
if (core === null) throw new Error("native_runner_authority_unavailable");
let reportedReconnectWait = false;
while (Date.now() < deadline) {
this.#throwIfFailed();
const connectionCount = core.activeRunnerConnectionCount();
if (connectionCount === 1) {
if (reportedReconnectWait) {
this.#diagnostic(
"warm runner re-authenticated before authority rotation",
);
}
return;
}
if (connectionCount > 1) {
throw new Error(
`native_runner_warm_attachment_ambiguous: expected one authenticated runner, found ${connectionCount}`,
);
}
if (!reportedReconnectWait) {
reportedReconnectWait = true;
this.#diagnostic(
"warm runner connection interrupted; waiting for re-authentication before authority rotation",
);
}
if (await this.#runnerHasExited()) {
throw new Error(
"native_runner_warm_attachment_runner_exited: runner exited before authority rotation",
);
}
await Promise.race([
new Promise<void>((resolveWait) => setTimeout(resolveWait, 25)),
this.#failureSignal,
]);View on GitHub (pinned to 01ad858492)
Solutions
- Kill the stale/duplicate runner process so only one remains
- Verify only one runnerd instance is launched per run (check process list / supervision config)
- Retry rotation after the old connection has fully torn down
- Report a bug if the transport itself is creating duplicate connections
Example fix
// before
// rotation attempted immediately after spawn
spawnRunner();
await transport.rotateAuthority();
// after
spawnRunner();
await waitFor(() => transport.activeRunnerConnectionCount() === 1, { timeout: 5000 });
await transport.rotateAuthority(); Defensive patterns
Strategy: validation
Validate before calling
const count = transport.activeRunnerConnectionCount?.() ?? 0;
if (count > 1) throw new Error(`duplicate runner connections: ${count}`); Try / catch
try {
await transport.rotateAuthority();
} catch (e) {
if (String(e.message).startsWith('native_runner_warm_attachment_ambiguous')) {
await killDuplicateRunners();
await retryRotation();
} else throw e;
} Prevention
- Ensure your supervisor launches exactly one runner process per run
- Wait for the old runner connection to fully close before spawning a replacement
- Monitor activeRunnerConnectionCount and alert on values >1
When it happens
Trigger: #awaitWarmRunnerConnection polls activeRunnerConnectionCount() and observes >1 while waiting for the old runner to be replaced by the re-authenticated one; duplicate runner processes authenticating during the rotation window.
Common situations: Two runner processes launched by accident (stale runner still alive plus a new one); a reconnect race where the old connection hasn't been dropped when the new one authenticates.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- native_runner_warm_attachment_not_quiescent
- native_runner_warm_attachment_runner_exited: runner exited b
- native_runner_authority_unavailable
- provider_transport_failed: warm runner did not re-authentica
- native_runner_prp_run_rotation_unavailable
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/a59d7722e269bec1.
Report an issue: GitHub.