{"record":{"id":"1a3e53884e46991d","repo":"justjavac/wechat-miniapp-radar","slug":"database-url-is-required-for-database-operations","errorCode":null,"errorMessage":"DATABASE_URL is required for database operations.","messagePattern":"DATABASE_URL is required for database operations\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"db/client.ts","lineNumber":21,"sourceCode":"import * as schema from \"@/db/schema\";\n\nfunction connectDb(databaseUrl: string) {\n  const client = postgres(databaseUrl, {\n    max: 1,\n    prepare: false\n  });\n\n  return {\n    client,\n    db: drizzle(client, { schema })\n  };\n}\n\nconst cachedConnections = new Map<string, ReturnType<typeof connectDb>>();\n\nexport function createDb(databaseUrl = process.env.DATABASE_URL) {\n  if (!databaseUrl) {\n    throw new Error(\"DATABASE_URL is required for database operations.\");\n  }\n\n  const cached = cachedConnections.get(databaseUrl);\n  if (cached) return cached.db;\n\n  const connection = connectDb(databaseUrl);\n  cachedConnections.set(databaseUrl, connection);\n  return connection.db;\n}\n\nexport async function closeDb(databaseUrl?: string) {\n  if (databaseUrl) {\n    const cached = cachedConnections.get(databaseUrl);\n    if (!cached) return;\n    cachedConnections.delete(databaseUrl);\n    await cached.client.end();\n    return;\n  }","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/justjavac/wechat-miniapp-radar/blob/02a010ecea0320b7aa975bb62a5dde271ae630c9/db/client.ts#L3-L39","documentation":"Thrown by createDb() in db/client.ts when no DATABASE_URL is available. The function defaults its only parameter to process.env.DATABASE_URL and rejects any falsy value before connectDb() runs, because drizzle/postgres-js cannot build a client without a connection string. It is a hard precondition: the cache lookup and connection never execute, so the caller must guarantee the value. Optional callers such as persistEnrichment() in lib/enrichment.ts guard with `if (!process.env.DATABASE_URL) return false;` before calling createDb(), so this throw only reaches code that calls createDb() unconditionally.","triggerScenarios":"Calling createDb() when process.env.DATABASE_URL is unset or empty and no explicit databaseUrl argument is supplied; importing a module that constructs the drizzle client at load time in a shell where the var was never injected (no `source .env`, a Vercel/CI job missing the secret, or a test runner that does not load .env).","commonSituations":"Forgetting to copy .env.example to .env locally; the var set in Vercel Preview but missing in Production; DATABASE_URL exported as an empty string by a wrapper; running db:import:test or db:verify without a configured DATABASE_URL (and without EXPECT_DATABASE=1).","solutions":["Set DATABASE_URL to a valid postgres connection string in .env locally and in Vercel project environment for deployments.","If you cannot provide a database, do not call createDb(): mirror persistEnrichment() and early-return when process.env.DATABASE_URL is falsy.","Pass an explicit URL, e.g. createDb('postgres://user:pass@host/db'), in scripts/tests so the function does not depend on env.","Verify the result with EXPECT_DATABASE=1 npm run db:verify once configured."],"exampleFix":"// before\nconst db = createDb(); // throws when DATABASE_URL is unset\n\n// after\nif (!process.env.DATABASE_URL) {\n  return { persisted: false };\n}\nconst db = createDb();","handlingStrategy":"validation","validationCode":"const hasDatabase = Boolean(process.env.DATABASE_URL?.trim());\nif (!hasDatabase) {\n  // skip DB-dependent work instead of calling createDb()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always gate createDb() behind a process.env.DATABASE_URL check, mirroring persistEnrichment().","Keep DATABASE_URL out of git; load it via .env locally and Vercel project env in deployments.","Run EXPECT_DATABASE=1 npm run db:verify in CI to fail fast on a missing or misconfigured string."],"tags":["database","configuration","environment","startup"],"backgroundTag":null,"analyzedSha":"02a010ecea0320b7aa975bb62a5dde271ae630c9","analyzedAt":"2026-08-12T16:16:33.227Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}