paperclipai/paperclip · error · Error
--api-key and --api-key-env are mutually exclusive.
Error message
--api-key and --api-key-env are mutually exclusive.
What it means
After a warm transition, the transport polls the runner store until the recovered identity matches the desired identity and the warm transition completes. If the identity has not converged within the grace period (`runnerReconnectGraceMs`, default 5s), or the runner process exited while waiting, it throws this error indicating recovery never finished in time.
Source
Thrown at cli/src/commands/test-drive.ts:228
"DATABASE_MIGRATION_URL from the selected data directory's .env, or choose a fresh --data-dir.",
);
}
const config = readConfigFile(configPath);
if (config?.database.mode === "postgres") {
throw new Error(
"test-drive cannot reuse a data directory configured for an external PostgreSQL database. " +
"Choose a fresh data directory or change database.mode to embedded-postgres.",
);
}
}
export function resolveTestDriveBootstrap(
options: TestDriveOptions,
env: NodeJS.ProcessEnv = process.env,
): ResolvedTestDriveBootstrap {
if (options.apiKey !== undefined && options.apiKeyEnv !== undefined) {
throw new Error("--api-key and --api-key-env are mutually exclusive.");
}
const harness = options.harness ?? "claude";
const definition = HARNESS_DEFINITIONS[harness];
if (!definition) {
throw new Error(`Unsupported test-drive harness: ${String(harness)}.`);
}
const companyName = (options.companyName ?? "Test Company").trim();
const agentName = (options.agentName ?? "CEO").trim();
if (!companyName) throw new Error("--company-name cannot be empty.");
if (!agentName) throw new Error("--agent-name cannot be empty.");
const model = options.model;
if (model !== undefined && (!model || model.trim() !== model)) {
throw new Error("--model cannot be empty or have surrounding whitespace.");
}
if (View on GitHub (pinned to 01ad858492)
Solutions
- Increase `runnerReconnectGraceMs` to allow slower warm recovery to finish (e.g. 30_000).
- Inspect runnerd logs for a crash during the transition and fix the underlying exit (memory, binary path, config).
- Retry the warm transition once the runner is healthy, or fall back to a cold start.
Example fix
// before
new RunnerdCodexTransport({ runnerReconnectGraceMs: 5_000 });
// after
new RunnerdCodexTransport({ runnerReconnectGraceMs: 30_000 }); Defensive patterns
Strategy: retry
Validate before calling
const graceMs = options.runnerReconnectGraceMs ?? 5_000;
if (graceMs < 10_000) console.warn("warm transition grace period may be too short on slow hosts"); Type guard
null
Try / catch
try {
await transport.startTurn(input);
} catch (e) {
if (e.message === "native_runner_warm_transition_recovery_pending" && runnerAlive()) {
await retryWithBackoff(() => transport.startTurn(input), { retries: 2 });
}
} Prevention
- Set runnerReconnectGraceMs generously (30s+) on slow or heavily loaded hosts.
- Monitor runnerd liveness so crashes are distinguished from slow recovery.
- Retry warm transitions with backoff before falling back to cold start.
When it happens
Trigger: The wait loop at the transition point times out (`Date.now() >= deadline`) or `#runnerHasExited()` observes the runnerd process died before `recoveryIdentityMatches` became true and `warmTransition` cleared.
Common situations: Slow or overloaded machine where the runner cannot recover within the default 5s grace; runner crash mid-transition (OOM, bad binary); setting `runnerReconnectGraceMs` too low for large session state restores.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- test-drive requires its isolated embedded database. Remove D
- test-drive cannot reuse a data directory configured for an e
- Unsupported test-drive harness: ${String(harness)}.
- runner_prp_command_timeout:${command.commandId}
- Failed to stop Daytona sandbox during lease release: ${forma
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/9355652078edf34c.
Report an issue: GitHub.