{"record":{"id":"0148e8a81ab1e04d","repo":"paperclipai/paperclip","slug":"embedded-bootstrap-data-directory-does-not-match-the-running","errorCode":null,"errorMessage":"Embedded bootstrap data directory does not match the running postmaster","messagePattern":"Embedded bootstrap data directory does not match the running postmaster","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/db/scripts/create-auth-bootstrap-invite.ts","lineNumber":45,"sourceCode":"    throw new Error(\"Usage: tsx create-auth-bootstrap-invite.ts --config <path> --base-url <url>\");\n  }\n\n  const config = JSON.parse(readFileSync(path.resolve(configPath), \"utf8\")) as {\n    database?: {\n      mode?: string;\n      embeddedPostgresPort?: number;\n      embeddedPostgresDataDir?: string;\n      connectionString?: string;\n    };\n  };\n  // The server can select another port when the configured one is occupied.\n  // Bind bootstrap to this data directory's running process, never another instance.\n  let embeddedPort: number | undefined;\n  if (config.database?.mode !== \"postgres\") {\n    const dataDir = config.database?.embeddedPostgresDataDir;\n    if (!dataDir) throw new Error(\"Embedded bootstrap requires its configured data directory\");\n    const pidLines = readFileSync(path.join(dataDir, \"postmaster.pid\"), \"utf8\").split(/\\r?\\n/);\n    if (realpathSync(pidLines[1] ?? \"\") !== realpathSync(dataDir)) throw new Error(\"Embedded bootstrap data directory does not match the running postmaster\");\n    const postmasterPid = Number(pidLines[0]);\n    if (!Number.isInteger(postmasterPid) || postmasterPid <= 1) throw new Error(\"Invalid embedded postmaster PID\");\n    process.kill(postmasterPid, 0);\n    embeddedPort = Number(pidLines[3]);\n    if (!Number.isInteger(embeddedPort) || embeddedPort < 1 || embeddedPort > 65535) throw new Error(\"Invalid running embedded database port\");\n  }\n  const dbUrl =\n    config.database?.mode === \"postgres\"\n      ? config.database.connectionString\n      : `postgres://paperclip:paperclip@127.0.0.1:${embeddedPort}/paperclip`;\n  if (!dbUrl) {\n    throw new Error(`Could not resolve database connection from ${configPath}`);\n  }\n\n  const db = createDb(dbUrl);\n  const closableDb = db as typeof db & {\n    $client?: {\n      end?: (options?: { timeout?: number }) => Promise<void>;","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/db/scripts/create-auth-bootstrap-invite.ts#L27-L63","documentation":"The script reads postmaster.pid from the configured data directory and verifies pidLines[1] (the data directory recorded by the postmaster) resolves to the same real path as the configured directory. A mismatch means the PID file belongs to a different instance — e.g. the data dir was moved, symlinked, or the config points at a copy — and the script refuses to touch that process.","triggerScenarios":"realpathSync(pidLines[1]) !== realpathSync(dataDir) while reading <dataDir>/postmaster.pid in non-postgres mode.","commonSituations":"Configured embeddedPostgresDataDir moved/renamed after the server started; data dir accessed via a symlink while postmaster recorded the real path; two dev instances and the config points at the wrong one; stale postmaster.pid copied with the directory.","solutions":["Correct config.database.embeddedPostgresDataDir to match the directory the running postmaster actually uses (read pidLines[1] of postmaster.pid).","Restart the dev server so postmaster.pid is regenerated for the current directory.","Remove symlinks — configure the real resolved path.","Delete a stale postmaster.pid only after confirming no postgres process is running, then restart."],"exampleFix":"// before\nembeddedPostgresDataDir: \"./data/pglite-link\" // symlink\n// after\nembeddedPostgresDataDir: \"/abs/path/to/project/data/pglite\" // realpath matching postmaster.pid line 2","handlingStrategy":"validation","validationCode":"const pid = readFileSync(path.join(dataDir, \"postmaster.pid\"), \"utf8\").split(/\\r?\\n/);\nif (realpathSync(pid[1] ?? \"\") !== realpathSync(dataDir)) throw new Error(\"postmaster belongs to a different data dir\");","typeGuard":null,"tryCatchPattern":"try { await main(); } catch (e) {\n  if (e.message.includes(\"does not match the running postmaster\")) { console.error(\"restarting dev server to regenerate postmaster.pid\"); }\n  throw e;\n}","preventionTips":["Never move or symlink the embedded data dir while the server is running","Point config at the realpath of the data directory","Confirm only one dev instance uses a given data dir","If the pid file is stale (no live postgres), remove it and restart cleanly"],"tags":["database","embedded-postgres","pid-file","config"],"backgroundTag":"internal-invariant-violation","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}