paperclipai/paperclip · error

database_unavailable

Error message

database_unavailable

What it means

This is an HTTP 503 JSON error from POST /dev-server/restart in the health router. The route first confirms a restart is actually required from persisted dev-server supervisor status; only then does it need the database handle to run a preflight query for active heartbeat runs before writing a hot-restart intent. When the `db` handle was never injected into healthRoutes (it is optional), the route cannot safely coordinate the restart and returns `database_unavailable` with status 503.

Source

Thrown at server/src/routes/health.ts:161

    }

    const persistedDevServerStatus = readPersistedDevServerStatus();
    if (!persistedDevServerStatus) {
      res.status(404).json({ error: "dev_server_supervisor_unavailable" });
      return;
    }

    const restartRequired =
      persistedDevServerStatus.dirty ||
      persistedDevServerStatus.changedPathCount > 0 ||
      persistedDevServerStatus.pendingMigrations.length > 0;
    if (!restartRequired) {
      res.status(409).json({ error: "restart_not_required" });
      return;
    }

    if (!db) {
      res.status(503).json({ error: "database_unavailable" });
      return;
    }

    const requestId = randomUUID();
    const requestedAt = new Date();
    const serverInfo = opts.serverInfo ?? getServerInfoSnapshot();
    const preflightActiveRunIds = await db
      .select({ id: heartbeatRuns.id })
      .from(heartbeatRuns)
      .where(eq(heartbeatRuns.status, "running"))
      .then((rows) => rows.map((row) => row.id));
    let intent: Awaited<ReturnType<typeof writeHotRestartIntent>> | null = null;
    try {
      intent = await writeHotRestartIntent({
        previousServerPid: process.pid,
        previousServerIdentity: serverInfo.processStartedAt,
        previousServerVersion: serverVersion,
        preflightActiveRunIds,

View on GitHub (pinned to 01ad858492)

Solutions

  1. Restart the server ensuring the database initializes before health routes are wired (set DATABASE_URL or allow embedded PGlite setup to complete).
  2. Check startup logs for DB init failure (connection refused, bad DATABASE_URL) and fix the connection first.
  3. If using embedded dev DB, remove data/pglite and re-run `pnpm dev` for a clean initialization.
  4. Verify the code path that constructs healthRoutes passes the `db` argument once the DB client exists.
  5. As a stopgap, perform a cold restart of the dev server instead of the hot-restart endpoint.

Example fix

// before: health routes wired without a db handle when DB is optional
createHealthRouter({ deploymentMode, authReady });
// after: pass the initialized db so preflight can run
if (!db) throw new Error("database unavailable at startup");
createHealthRouter({ deploymentMode, authReady }, db);
Defensive patterns

Strategy: retry

Validate before calling

// before calling the restart endpoint
const health = await fetch('/api/health').then(r => r.json());
if (!health.database || health.database.status !== 'ok') {
  throw new Error('database not available; hot restart cannot preflight active runs');
}

Type guard

function isDbUnavailable(err: { status?: number; error?: string }): boolean {
  return err.status === 503 && err.error === 'database_unavailable';
}

Try / catch

const res = await api.post('/api/dev-server/restart');
if (res.status === 503 && (await res.json()).error === 'database_unavailable') {
  await waitForDbReady({ timeoutMs: 30000 });
  return retryRestart();
}

Prevention

When it happens

Trigger: POST /api/dev-server/restart is called when the persisted dev-server status says a restart IS required (dirty, changedPathCount > 0, or pendingMigrations) but the server was constructed without a `db` instance, so the preflight active-run check cannot run.

Common situations: Starting the server in a mode where the DB client is intentionally not wired (embedded PGlite not initialized, DATABASE_URL unset and init failed); clicking "Restart now" in the dev UI while the server booted degraded without a database; partial startup where health routes registered before DB init completed.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/25ade9eb5ecd3453. Report an issue: GitHub.