paperclipai/paperclip · critical · Error
Refusing embedded PostgreSQL recovery because the data direc
Error message
Refusing embedded PostgreSQL recovery because the data directory reports a live process (pid=${runningPostgresPid}) What it means
When embedded PostgreSQL exits unexpectedly, the supervisor tries to recover by restarting it, but first re-checks the postmaster.pid in the data directory. If the pid recorded there is still a live process (process.kill(pid, 0) succeeds), restarting could corrupt a data directory that another running postmaster owns, so recovery is refused. This is a safety stop, not a transient failure.
Source
Thrown at server/src/index.ts:572
});
}
} else {
logger.info(`Embedded PostgreSQL cluster already exists (${clusterVersionFile}); skipping init`);
}
if (existsSync(postmasterPidFile)) {
logger.warn("Removing stale embedded PostgreSQL lock file");
rmSync(postmasterPidFile, { force: true });
}
try {
await embeddedPostgres.start();
} catch (err) {
logEmbeddedPostgresFailure("start", err);
throw formatEmbeddedPostgresError(err, {
fallbackMessage: `Failed to start embedded PostgreSQL on port ${port}`,
recentLogs: logBuffer.getRecentLogs(),
});
}
embeddedPostgresStartedByThisProcess = true;
embeddedPostgresSupervisor = createEmbeddedPostgresSupervisor({
initialInstance: embeddedPostgres,
createInstance: createEmbeddedPostgres,
beforeRestart: () => {
const runningPostgresPid = getRunningPid();
if (runningPostgresPid) {
throw new Error(`Refusing embedded PostgreSQL recovery because the data directory reports a live process (pid=${runningPostgresPid})`);
}
if (existsSync(postmasterPidFile)) rmSync(postmasterPidFile, { force: true });
},
onUnexpectedExit: (code, signal) => logger.error(
{ code, signal, recentLogs: logBuffer.getRecentLogs() },
"Embedded PostgreSQL exited unexpectedly; attempting recovery",
),
onRestartAttemptFailed: (err, attempt) => logger.error(
{ err, attempt, recentLogs: logBuffer.getRecentLogs() },
"Embedded PostgreSQL recovery attempt failed",View on GitHub (pinned to 01ad858492)
Solutions
- Identify the process: `ps -p <pid> -o pid,ppid,command` — confirm whether it is really a postgres postmaster.
- If it is a leftover Paperclip/postgres you own, shut it down gracefully (`pg_ctl stop -D <dataDir>` or stop the other Paperclip process), then restart the server so recovery can proceed.
- If the pid belongs to an unrelated process (pid reuse), verify no postgres owns the data dir, then remove the stale postmaster.pid manually and restart.
- Prevent recurrence: run only one embedded-mode server per data directory; prefer a managed Postgres via DATABASE_URL for parallel dev servers.
Example fix
# before: recovery refused, pid 4242 alive ps -p 4242 -o pid,command # leftover postmaster from a killed server pg_ctl stop -D ~/.paperclip/embedded-pg/data || kill 4242 # after: pid gone, restart the Paperclip server; supervisor recovery proceeds rm -f ~/.paperclip/embedded-pg/data/postmaster.pid # only if ps shows no postgres paperclip dev
Defensive patterns
Strategy: fallback
Validate before calling
import { existsSync, readFileSync } from "node:fs";
import path from "node:path";
function pidAlive(pid: number): boolean {
try { process.kill(pid, 0); return true; } catch { return false; }
}
function embeddedPgSafeToStart(dataDir: string): boolean {
const pidFile = path.join(dataDir, "postmaster.pid");
if (!existsSync(pidFile)) return true;
const pid = Number(readFileSync(pidFile, "utf8").split("\n")[0]);
return !Number.isInteger(pid) || pid <= 0 || !pidAlive(pid);
} Type guard
const isPostmasterPidStale = (dataDir: string): boolean => {
const pidFile = path.join(dataDir, "postmaster.pid");
if (!existsSync(pidFile)) return false;
const pid = Number(readFileSync(pidFile, "utf8").split("\n")[0]);
try { process.kill(pid, 0); return false; } catch { return true; }
}; Prevention
- Run only one embedded-mode Paperclip server per data directory.
- Shut down dev servers gracefully (SIGTERM) so postmaster cleans its pid file.
- For parallel dev servers, set DATABASE_URL to separate managed Postgres instances.
- On boot failures, check `ps aux | grep postgres` and the embedded PG log before deleting postmaster.pid.
When it happens
Trigger: beforeRestart hook in createEmbeddedPostgresSupervisor (server startup with no DATABASE_URL, embedded PG mode): embedded PG crashed or 'exited' from this process's view while a postmaster with the pid in postmaster.pid is still alive — e.g. a forked/orphaned postmaster, another Paperclip server instance sharing the data dir, or the pid got reused by an unrelated live process.
Common situations: Two dev servers started against the same PGlite/embedded data directory; a previous server killed with SIGKILL leaving the postmaster alive detached; container/PID-namespace weirdness where the recorded host pid maps to a live process; pid reuse on long-running machines after an unclean shutdown.
Related errors
- Failed to terminate local service ${target}${listener}
- [paperclip] sandbox callback bridge kept queued request ${re
- [paperclip] sandbox callback bridge failed to abort queued r
- Database mode is postgres but no connection string was set;
- failed company transfer runs stranded in applying by a resta
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-08-21).
Data as JSON: /api/errors/55b4aa32b84323ed.
Report an issue: GitHub.