{"record":{"id":"e8332dc9ced17bbd","repo":"paperclipai/paperclip","slug":"database-contract-unmet","errorCode":"database-contract-unmet","errorMessage":"authenticated public deployments require DATABASE_URL or config.database.connectionString; refusing embedded PostgreSQL fallback","messagePattern":"authenticated public deployments require DATABASE_URL or config\\.database\\.connectionString; refusing embedded PostgreSQL fallback","errorType":"exception","errorClass":"StartupRefusalError","httpStatus":null,"severity":"critical","filePath":"server/src/index.ts","lineNumber":334,"sourceCode":"    try {\n      const parsed = new URL(connectionString);\n      return parsed.protocol === \"postgres:\" || parsed.protocol === \"postgresql:\";\n    } catch {\n      return false;\n    }\n  }\n\n  function assertCloudDatabaseContract(): void {\n    if (config.deploymentMode !== \"authenticated\" || config.deploymentExposure !== \"public\") {\n      return;\n    }\n    if (!config.databaseUrl) {\n      // Under a managed-cloud supervisor a missing DATABASE_URL on boot\n      // is the config-application race (the container can start before\n      // the staged variables land), not operator error — the supervisor\n      // restarts once the config holds. A malformed value below is a\n      // real misconfiguration and stays an always-reported Error.\n      throw new StartupRefusalError(\n        \"database-contract-unmet\",\n        \"authenticated public deployments require DATABASE_URL or config.database.connectionString; refusing embedded PostgreSQL fallback\",\n      );\n    }\n    if (!isPostgresConnectionString(config.databaseUrl)) {\n      throw new Error(\n        \"authenticated public deployments require DATABASE_URL to be a postgres/postgresql connection string\",\n      );\n    }\n  }\n\n  const LOCAL_BOARD_USER_ID = \"local-board\";\n  const LOCAL_BOARD_USER_EMAIL = \"local@paperclip.local\";\n  const LOCAL_BOARD_USER_NAME = \"Board\";\n  \n  async function ensureLocalTrustedBoardPrincipal(db: any): Promise<void> {\n    const now = new Date();\n    const existingUser = await db","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/index.ts#L316-L352","documentation":"assertCloudDatabaseContract enforces that authenticated public cloud deployments must have an explicit external PostgreSQL connection (DATABASE_URL env var or config.database.connectionString). If config.databaseUrl is missing at boot, it throws a StartupRefusalError with code database-contract-unmet, refusing to silently fall back to the embedded PostgreSQL (PGlite) database. This protects authenticated deployments from accidentally booting with a local, non-persistent database.","triggerScenarios":"startServerWithDatabaseTelemetry/boot runs in authenticated-public deployment mode where config.databaseUrl is falsy — DATABASE_URL env var unset AND config.database.connectionString unset. Comment in source notes this can transiently happen under a managed-cloud supervisor when the container starts before staged config variables land.","commonSituations":"Kubernetes/cloud supervisor race where the pod starts before DATABASE_URL is injected; deployment manifest missing the env var; secret not mounted; staging config not yet applied; forgetting the connection string when promoting a dev (embedded) configuration to production.","solutions":["Set DATABASE_URL (or config.database.connectionString) to a valid PostgreSQL connection string in the deployment environment/secret store and restart","If this is a supervisor config race, verify staged variables and let the supervisor restart the container — the next boot with the variable present will pass","Audit the deployment manifest (env/secret references) so DATABASE_URL is guaranteed present for authenticated public deployments","Confirm the deployment mode is actually authenticated-public; dev/local deployments intentionally allow the embedded fallback by leaving DATABASE_URL unset"],"exampleFix":"// before (deployment env)\n# DATABASE_URL not set -> StartupRefusalError: database-contract-unmet\n// after\nDATABASE_URL=postgres://user:pass@db-host:5432/paperclip\n# or in config\ndatabase: { connectionString: 'postgres://user:pass@db-host:5432/paperclip' }","handlingStrategy":"validation","validationCode":"// at deploy time / pre-boot check\nif (process.env.DEPLOYMENT_MODE === 'authenticated-public' && !process.env.DATABASE_URL && !config.database?.connectionString) { throw new Error('authenticated public deployment missing DATABASE_URL'); }","typeGuard":"null","tryCatchPattern":"try { await startServerWithDatabaseTeardown(); } catch (e) { if (e instanceof StartupRefusalError && e.code === 'database-contract-unmet') { // surface to operator: missing DATABASE_URL; do not retry with embedded fallback } else throw e; }","preventionTips":["Set DATABASE_URL in the deployment manifest/secret store for every authenticated public environment","Verify env/secret mounts in CI before rollout","Understand dev allows embedded PGlite but authenticated public deployments intentionally refuse it","Allow the supervisor to restart once staged config lands — do not weaken the refusal"],"tags":["startup","database","config","deployment","env"],"backgroundTag":"missing-env-var","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}