paperclipai/paperclip · warning
Request failed
Error message
Request failed: ${response.status} What it means
A startup warning (logger.warn) from Paperclip's embedded-PostgreSQL bootstrap in server/src/index.ts:431, not a thrown error. When DATABASE_URL is unset, the server resolves the embedded data dir (config.embeddedPostgresDataDir) and reads its postmaster.pid: if the first line parses to a positive integer pid and that pid is alive (checked with process.kill(pid, 0)), another PostgreSQL postmaster already owns this cluster. The server deliberately skips init/start and attaches to the existing process instead of launching a second postmaster against the same data directory (which would corrupt it).
Solutions
- If a second server against the same DB is intentional, no action is needed - the server reuses the running postgres; note the pid and port from the message.
- Otherwise stop the leftover postgres: verify with `ps -p <pid> -o comm=` then `kill <pid>` (or `lsof -ti :54329 | xargs kill`), and restart the server so it manages the lifecycle itself.
- For parallel instances, give each its own data dir and port via config database.embeddedPostgresDataDir / database.embeddedPostgresPort, or set DATABASE_URL to an external postgres.
- For a clean-slate dev cluster, stop all processes using the data dir, then delete the embedded data dir so the next start re-runs initdb (migrations re-apply automatically on first run).
Example fix
// before: two dev servers share the default embedded data dir
// second start logs: "Embedded PostgreSQL already running; reusing existing process (pid=1234, port=54329)"
// after (paperclip.config.json for the second instance): dedicated data dir + port
{
"database": {
"embeddedPostgresDataDir": "~/.paperclip/embedded-postgres-2",
"embeddedPostgresPort": 54330
}
} Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
const isPidAlive = (pid: number): boolean => {
try { process.kill(pid, 0); return true; } catch { return false; }
};
// Run before starting a second server against the same data dir
export function embeddedPostgresRunning(dataDir: string): number | null {
const pidFile = resolve(dataDir, "postmaster.pid");
if (!existsSync(pidFile)) return null;
const pidLine = readFileSync(pidFile, "utf8").split("\n")[0]?.trim();
const pid = Number(pidLine);
return Number.isInteger(pid) && pid > 0 && isPidAlive(pid) ? pid : null;
} Type guard
function isEmbeddedPostgresLive(dataDir: string): boolean {
const pid = embeddedPostgresRunning(dataDir); // helper above
return typeof pid === "number"; // true => a second start will reuse it
} Prevention
- Shut the dev server down cleanly so the embedded postgres child stops with it; verify with `lsof -ti :54329` before starting another instance.
- Give each concurrent instance (worktrees, CI jobs) its own database.embeddedPostgresDataDir and embeddedPostgresPort.
- Treat the 'already running; reusing' message as expected reuse, but confirm the logged pid is a postgres process (`ps -p <pid> -o comm=`) before relying on it.
When it happens
Trigger: Running `pnpm dev` (or any server start without DATABASE_URL) while a previous Paperclip server process or its orphaned embedded postgres child is still alive and using the same embeddedPostgresDataDir; e.g. the API server was killed but the postgres child survived, or a second checkout/worktree was started with the default data dir and port 54329.
Common situations: Dev loop where Ctrl-C on the server leaves the embedded postgres child running; two worktrees or two terminals sharing the default embedded data dir; CI runners that reuse a persisted data dir between jobs; a manually started postgres pointed at the same data directory.
Related errors
- Cannot seed target embedded PostgreSQL at
- CLI auth challenge was cancelled.
- Embedded bootstrap data directory does not match the…
- Embedded bootstrap requires its configured data directory
- Invalid embedded postmaster PID
AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18).
Data as JSON: /api/errors/023c67b1bcadb5a6.
Report an issue: GitHub.
Appendix: source
Thrown at cli/src/client/board-auth.ts:171
if (init?.body !== undefined && !headers.has("content-type")) {
headers.set("content-type", "application/json");
}
if (!headers.has("accept")) {
headers.set("accept", "application/json");
}
const response = await fetch(url, {
...init,
headers,
});
if (!response.ok) {
const body = await response.json().catch(() => null);
const message =
body && typeof body === "object" && typeof (body as { error?: unknown }).error === "string"
? (body as { error: string }).error
: `Request failed: ${response.status}`;
throw new Error(message);
}
return response.json() as Promise<T>;
}
export async function openUrl(url: string): Promise<boolean> {
const { command, args } =
process.platform === "darwin"
? { command: "open", args: [url] }
: process.platform === "win32"
? { command: "cmd", args: ["/c", "start", "", url] }
: { command: "xdg-open", args: [url] };
return new Promise<boolean>((resolve) => {
let child: ChildProcess;
try {
child = spawn(command, args, { detached: true, stdio: "ignore" });
} catch {View on GitHub (pinned to 120ae5428f)