{"record":{"id":"14aa82466c9f2e36","repo":"thedotmack/claude-mem","slug":"postgres-requires-claude-mem-server-database-url","errorCode":null,"errorMessage":"Postgres requires CLAUDE_MEM_SERVER_DATABASE_URL","messagePattern":"Postgres requires CLAUDE_MEM_SERVER_DATABASE_URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/storage/postgres/config.ts","lineNumber":32,"sourceCode":"  env?: NodeJS.ProcessEnv;\n  requireDatabaseUrl?: boolean;\n}\n\nconst DEFAULT_POOL_MAX = 10;\nconst DEFAULT_IDLE_TIMEOUT_MS = 30_000;\nconst DEFAULT_CONNECTION_TIMEOUT_MS = 5_000;\nconst DEFAULT_STATEMENT_TIMEOUT_MS = 30_000;\n\nexport function getPostgresDatabaseUrl(env: NodeJS.ProcessEnv = process.env): string | null {\n  return env.CLAUDE_MEM_SERVER_DATABASE_URL || null;\n}\n\nexport function parsePostgresConfig(options: ParsePostgresConfigOptions = {}): PostgresConfig | null {\n  const env = options.env ?? process.env;\n  const connectionString = getPostgresDatabaseUrl(env);\n  if (!connectionString) {\n    if (options.requireDatabaseUrl) {\n      throw new Error('Postgres requires CLAUDE_MEM_SERVER_DATABASE_URL');\n    }\n    return null;\n  }\n\n  return {\n    connectionString,\n    max: parsePositiveInt(env.CLAUDE_MEM_POSTGRES_POOL_MAX, DEFAULT_POOL_MAX),\n    idleTimeoutMillis: parsePositiveInt(env.CLAUDE_MEM_POSTGRES_IDLE_TIMEOUT_MS, DEFAULT_IDLE_TIMEOUT_MS),\n    connectionTimeoutMillis: parsePositiveInt(env.CLAUDE_MEM_POSTGRES_CONNECTION_TIMEOUT_MS, DEFAULT_CONNECTION_TIMEOUT_MS),\n    statementTimeoutMillis: parsePositiveInt(env.CLAUDE_MEM_POSTGRES_STATEMENT_TIMEOUT_MS, DEFAULT_STATEMENT_TIMEOUT_MS),\n    ssl: parseSsl(connectionString, env)\n  };\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number): number {\n  if (!value) {\n    return fallback;\n  }","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/storage/postgres/config.ts#L14-L50","documentation":"Thrown by parsePostgresConfig when called with requireDatabaseUrl:true but env.CLAUDE_MEM_SERVER_DATABASE_URL is unset/empty. Without requireDatabaseUrl the function returns null (allowing SQLite fallback); requiring it makes the absence fatal, since the caller needs a Postgres backend specifically.","triggerScenarios":"parsePostgresConfig({ requireDatabaseUrl: true }) (or a caller that sets it) invoked in an environment where CLAUDE_MEM_SERVER_DATABASE_URL is not set.","commonSituations":"Server configured to use the Postgres backend but the connection string env var wasn't provided; deployment forgot to inject the secret; .env not loaded in the process; misnamed variable.","solutions":["Set CLAUDE_MEM_SERVER_DATABASE_URL to a valid Postgres connection string (e.g., postgres://user:pass@host:5432/db).","Confirm the env var is actually visible to the process (print process.env keys, never the value).","If you did not intend to require Postgres, call parsePostgresConfig without requireDatabaseUrl so it returns null and falls back to SQLite.","Use a secret manager / devkey to inject the value rather than hardcoding."],"exampleFix":"// before\nconst cfg = parsePostgresConfig({ requireDatabaseUrl: true }); // throws if unset\n\n// after\nexport CLAUDE_MEM_SERVER_DATABASE_URL='postgres://...' \nconst cfg = parsePostgresConfig({ requireDatabaseUrl: true });","handlingStrategy":"validation","validationCode":"if (options.requireDatabaseUrl && !process.env.CLAUDE_MEM_SERVER_DATABASE_URL) {\n  throw new Error('CLAUDE_MEM_SERVER_DATABASE_URL must be set to use Postgres');\n}\nconst cfg = parsePostgresConfig(options);","typeGuard":null,"tryCatchPattern":"try {\n  const cfg = parsePostgresConfig({ requireDatabaseUrl: true });\n} catch (err) {\n  if (err instanceof Error && /CLAUDE_MEM_SERVER_DATABASE_URL/.test(err.message)) {\n    // fall back to SQLite or halt with a config error\n    logger.error('DB', 'Postgres URL missing — falling back to SQLite');\n    return null;\n  }\n  throw err;\n}","preventionTips":["Provide CLAUDE_MEM_SERVER_DATABASE_URL via a secret manager in all Postgres environments.","Only pass requireDatabaseUrl when Postgres is mandatory; otherwise allow SQLite fallback.","Verify env vars are injected into the process before startup."],"tags":["postgres","config","environment","secrets","database"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}