{"record":{"id":"4726436c87daf29e","repo":"thedotmack/claude-mem","slug":"server-startup-configuration-is-invalid","errorCode":null,"errorMessage":"server startup configuration is invalid:","messagePattern":"server startup configuration is invalid:","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/server/runtime/create-server-service.ts","lineNumber":144,"sourceCode":"    }\n  }\n\n  const hasDatabaseUrl = Boolean((env.CLAUDE_MEM_SERVER_DATABASE_URL ?? '').trim());\n  if (!hasDatabaseUrl) {\n    errors.push('CLAUDE_MEM_SERVER_DATABASE_URL is required to start the server (Postgres connection string).');\n  }\n\n  const hasRedisUrl = Boolean((env.CLAUDE_MEM_REDIS_URL ?? '').trim());\n  if (queueEngine === 'bullmq' && !hasRedisUrl) {\n    errors.push('CLAUDE_MEM_REDIS_URL is required when CLAUDE_MEM_QUEUE_ENGINE=bullmq.');\n  }\n\n  if (errors.length > 0) {\n    const message = [\n      'server startup configuration is invalid:',\n      ...errors.map(line => `  - ${line}`),\n    ].join('\\n');\n    throw new Error(message);\n  }\n\n  return {\n    isDocker,\n    // Phase 1a: report the canonical `'server'` value when unset; legacy\n    // `'server-beta'` is preserved verbatim when explicitly supplied so\n    // diagnostics reflect the operator's actual config.\n    runtime: runtime || 'server',\n    authMode,\n    queueEngine: queueEngine || 'disabled',\n    hasDatabaseUrl,\n    hasRedisUrl,\n  };\n}\n\n// #2443 — the server runtime must load an observation mode before it can\n// process any generation job; without it every job fails with \"No mode\n// loaded\". We mirror the worker's pattern (src/services/worker-service.ts) and","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/server/runtime/create-server-service.ts#L126-L162","documentation":"validateServerEnv performs fail-fast environment validation before the claude-mem server can start. It aggregates every invalid combination of CLAUDE_MEM_* variables (runtime, auth mode, queue engine, database URL, Redis URL) — with stricter rules when a Docker environment is detected — and throws a single Error whose message is a bulleted list of all problems found. The multi-line format lets operators fix every issue in one restart instead of discovering them one at a time.","triggerScenarios":"Calling createServerService() or runServerGenerationWorker() when: CLAUDE_MEM_RUNTIME is set to something other than 'server'/'server-beta' inside Docker; CLAUDE_MEM_AUTH_MODE=local-dev in Docker; CLAUDE_MEM_ALLOW_LOCAL_DEV_BYPASS=1|true in Docker; CLAUDE_MEM_QUEUE_ENGINE missing or not 'bullmq' in Docker; CLAUDE_MEM_SERVER_DATABASE_URL unset; or CLAUDE_MEM_REDIS_URL unset while queue engine is bullmq.","commonSituations":"Starting the server container with a docker-compose env copied from a local-dev setup (local-dev auth, missing queue engine); forgetting CLAUDE_MEM_SERVER_DATABASE_URL after migrating to Postgres; leaving CLAUDE_MEM_RUNTIME=worker on the server image; running bullmq without a Redis URL; legacy scripts still exporting server-beta or the local-dev bypass flags.","solutions":["Read the bulleted list in the error message — each line names exactly one env variable to fix.","Set CLAUDE_MEM_SERVER_DATABASE_URL to a valid Postgres connection string (always required).","In Docker: set CLAUDE_MEM_QUEUE_ENGINE=bullmq and CLAUDE_MEM_REDIS_URL to your Redis instance.","In Docker: set CLAUDE_MEM_RUNTIME=server (or legacy server-beta) and CLAUDE_MEM_AUTH_MODE=api-key; create a key with `claude-mem server api-key create`; remove CLAUDE_MEM_ALLOW_LOCAL_DEV_BYPASS.","For local development outside Docker, keep local-dev auth/bypass settings but ensure the database URL is still provided."],"exampleFix":"// before (docker-compose env, fails)\nCLAUDE_MEM_RUNTIME=worker\nCLAUDE_MEM_AUTH_MODE=local-dev\nCLAUDE_MEM_QUEUE_ENGINE=\n# after\nCLAUDE_MEM_RUNTIME=server\nCLAUDE_MEM_AUTH_MODE=api-key\nCLAUDE_MEM_QUEUE_ENGINE=bullmq\nCLAUDE_MEM_REDIS_URL=redis://redis:6379\nCLAUDE_MEM_SERVER_DATABASE_URL=postgres://user:pass@db:5432/claude_mem","handlingStrategy":"validation","validationCode":"const required = ['CLAUDE_MEM_SERVER_DATABASE_URL'];\nconst docker = process.env.DOCKER_BUILD != null || process.env.container != null; // container detection\nif (docker) required.push('CLAUDE_MEM_QUEUE_ENGINE', 'CLAUDE_MEM_REDIS_URL');\nconst missing = required.filter(k => !(process.env[k] ?? '').trim());\nif (missing.length) throw new Error(`missing server env: ${missing.join(', ')}`);\nconst rt = (process.env.CLAUDE_MEM_RUNTIME ?? '').trim();\nif (docker && rt && rt !== 'server' && rt !== 'server-beta') throw new Error(`invalid CLAUDE_MEM_RUNTIME=${rt} in Docker`);","typeGuard":null,"tryCatchPattern":"try {\n  const service = await createServerService();\n} catch (err) {\n  if ((err as Error).message.startsWith('server startup configuration is invalid:')) {\n    // print each '  - ' line as a separate ops remediation item and abort boot\n  }\n  throw err;\n}","preventionTips":["Keep a single .env template for server deployments listing every CLAUDE_MEM_* variable with required markers.","Validate env at CI/container-build time (docker compose config + a startup healthcheck) rather than at runtime boot.","Never copy local-dev env files into Docker deployments; keep them in separate, named files.","After switching queue engine to bullmq, immediately pair it with CLAUDE_MEM_REDIS_URL."],"tags":["configuration","environment","startup","docker","validation"],"backgroundTag":"missing-required-config","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}