{"record":{"id":"0f2e4c303e6e80c3","repo":"paperclipai/paperclip","slug":"test-drive-cannot-reuse-a-data-directory-configure","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/test-drive.ts","lineNumber":216,"sourceCode":"\n  return { dataDir, linkedWorktree };\n}\n\nexport function assertTestDriveDatabaseIsolation(\n  configPath?: string,\n  env: NodeJS.ProcessEnv = process.env,\n  readConfigFile: (path?: string) => PaperclipConfig | null = readConfig,\n): void {\n  if (env.DATABASE_URL?.trim() || env.DATABASE_MIGRATION_URL?.trim()) {\n    throw new Error(\n      \"test-drive requires its isolated embedded database. Remove DATABASE_URL and \" +\n        \"DATABASE_MIGRATION_URL from the selected data directory's .env, or choose a fresh --data-dir.\",\n    );\n  }\n\n  const config = readConfigFile(configPath);\n  if (config?.database.mode === \"postgres\") {\n    throw new Error(\n      \"test-drive cannot reuse a data directory configured for an external PostgreSQL database. \" +\n        \"Choose a fresh data directory or change database.mode to embedded-postgres.\",\n    );\n  }\n}\n\nexport function resolveTestDriveBootstrap(\n  options: TestDriveOptions,\n  env: NodeJS.ProcessEnv = process.env,\n): ResolvedTestDriveBootstrap {\n  if (options.apiKey !== undefined && options.apiKeyEnv !== undefined) {\n    throw new Error(\"--api-key and --api-key-env are mutually exclusive.\");\n  }\n\n  const harness = options.harness ?? \"claude\";\n  const definition = HARNESS_DEFINITIONS[harness];\n  if (!definition) {\n    throw new Error(`Unsupported test-drive harness: ${String(harness)}.`);","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/cli/src/commands/test-drive.ts#L198-L234","documentation":"After re-registering both old and new endpoints during a warm transition, the transport verifies the NEW registered connection is connect-mode AND canonically identical to the connection recorded in the warm-recovery proof receipt. A mode mismatch or any canonical-JSON difference between the registered connection and the receipt throws this error, since the proof would no longer cover the actual endpoint.","triggerScenarios":"`controlPlaneRegistration` returns a connection whose `mode` is not \"connect\", or whose canonical JSON differs from `warmRecovery.proof.receipt.connection` (different URL, port, or extra fields).","commonSituations":"The control plane rewrites or normalizes the URL (adds/removes a trailing slash, swaps host) between registration and the receipt; a load balancer or proxy changes the advertised endpoint; a stale receipt from a previous identity being replayed.","solutions":["Make the registration return exactly the endpoint recorded in the warm-recovery proof receipt (byte-for-byte canonical JSON equal).","Re-issue the warm-recovery proof/receipt if the endpoint legitimately changed, so the receipt matches the new connection.","Check for proxies/control-plane middleware that mutates the registered connection and disable or fix it."],"exampleFix":"// before\nreceipt.connection = { mode: \"connect\", connectUrl: \"http://127.0.0.1:9100\" };\nregistered = { mode: \"connect\", connectUrl: \"http://localhost:9100/\" }; // mismatch\n// after\nregistered = { mode: \"connect\", connectUrl: \"http://127.0.0.1:9100\" }; // canonical match","handlingStrategy":"validation","validationCode":"const canonical = (v: unknown) => JSON.stringify(v, Object.keys((v as object)).sort());\nif (canonical(newConnection) !== canonical(receipt.connection)) {\n  throw new Error(\"registered connection does not match recovery receipt\");\n}","typeGuard":"function matchesReceipt(conn: unknown, receipt: { connection: unknown }): boolean {\n  return JSON.stringify(conn) === JSON.stringify(receipt.connection);\n}","tryCatchPattern":"try {\n  await transport.startTurn(input);\n} catch (e) {\n  if (e.message === \"native_runner_warm_transition_registered_endpoint_mismatch\") {\n    await requestNewWarmRecoveryProof(root, desiredIdentity); // refresh receipt to current endpoint\n  }\n}","preventionTips":["Issue recovery receipts from the same registration path that returns the connection so they cannot diverge.","Disable proxies/middleware that rewrite registered endpoints.","Compare endpoints with canonical JSON before attempting warm transitions."],"tags":["runner","warm-transition","endpoint","proof-verification"],"backgroundTag":"checksum-mismatch","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}