{"record":{"id":"d6d618291ec44350","repo":"thedotmack/claude-mem","slug":"server-commandlabel-is-a-server-runtime-comma","errorCode":null,"errorMessage":"`server ${commandLabel}` is a server runtime command, but CLAUDE_MEM_RUNTIME=${runtime}. Set CLAUDE_MEM_RUNTIME=server (and CLAUDE_MEM_SERVER_DATABASE_URL) to run server operations, or use the worker CLI (`worker-service ...`) for the worker runtime.","messagePattern":"`server (.+?)` is a server runtime command, but CLAUDE_MEM_RUNTIME=(.+?)\\. Set CLAUDE_MEM_RUNTIME=server \\(and CLAUDE_MEM_SERVER_DATABASE_URL\\) to run server operations, or use the worker CLI \\(`worker-service \\.\\.\\.`\\) for the worker runtime\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/server/runtime/ServerService.ts","lineNumber":493,"sourceCode":"// is invisible to the server runtime, which reads keys from Postgres. Use\n// this entrypoint inside Docker / Compose.\n// #2572 — wrong-runtime guard.\n//\n// The server operability commands (`api-key`, `keys`, `jobs`) only make\n// sense in the server runtime, whose canonical store is Postgres. If they\n// are invoked in a worker-only context — `CLAUDE_MEM_RUNTIME` set to `worker`,\n// or no `CLAUDE_MEM_SERVER_DATABASE_URL` configured — we fail fast with an\n// actionable message instead of crashing later with an opaque pool error.\n//\n// Phase 1d: dual-accept the persisted runtime literal (`'server'` is the new\n// canonical form; `'server-beta'` remains valid for existing installs).\nexport function assertServerRuntimeForCli(\n  commandLabel: string,\n  env: NodeJS.ProcessEnv = process.env,\n): void {\n  const runtime = (env.CLAUDE_MEM_RUNTIME ?? '').trim().toLowerCase();\n  if (runtime && runtime !== 'server' && runtime !== 'server-beta') {\n    throw new Error(\n      `\\`server ${commandLabel}\\` is a server runtime command, but CLAUDE_MEM_RUNTIME=${runtime}. ` +\n        'Set CLAUDE_MEM_RUNTIME=server (and CLAUDE_MEM_SERVER_DATABASE_URL) to run server operations, ' +\n        'or use the worker CLI (`worker-service ...`) for the worker runtime.',\n    );\n  }\n  if (!(env.CLAUDE_MEM_SERVER_DATABASE_URL ?? '').trim()) {\n    throw new Error(\n      `CLAUDE_MEM_SERVER_DATABASE_URL is required for \\`server ${commandLabel}\\`. ` +\n        'This command talks to the server Postgres backend; export the connection string before running it.',\n    );\n  }\n}\n\nexport async function runServerApiKeyCli(argv: string[]): Promise<void> {\n  const sub = argv[0]?.toLowerCase();\n  const options = parseFlagArgs(argv.slice(1));\n\n  try {","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/8bc631a71a487424b866756e43a6efa4574cc66b/src/server/runtime/ServerService.ts#L475-L511","documentation":"assertServerRuntimeForCli() guards `server <cmd>` CLI subcommands so they fail fast with actionable text instead of crashing later with an opaque Postgres pool error. It throws when CLAUDE_MEM_RUNTIME is set to a non-server value (typically 'worker'); the canonical 'server' and the legacy 'server-beta' literal are both accepted (Phase 1d dual-accept).","triggerScenarios":"Running `claude-mem server api-key create` (or any server subcommand) in a shell where CLAUDE_MEM_RUNTIME=worker is exported — e.g. the same environment used for worker/service operation; CI images that default the variable to worker; .env files shared between worker and server contexts.","commonSituations":"Operators managing both worker and server runtimes from one machine; docker/CI environments exporting a global CLAUDE_MEM_RUNTIME; scripts written before the runtime split that assume every command works everywhere.","solutions":["Export CLAUDE_MEM_RUNTIME=server (and CLAUDE_MEM_SERVER_DATABASE_URL) in the shell before running `server` subcommands.","If this machine is worker-only, use the worker CLI (`worker-service ...`) for worker-runtime operations instead.","Scope CLAUDE_MEM_RUNTIME=worker per-command rather than globally so it does not leak into server commands.","Remember 'server-beta' still works if your existing config uses it."],"exampleFix":"# before\nexport CLAUDE_MEM_RUNTIME=worker\nclaude-mem server api-key create\n\n# after\nexport CLAUDE_MEM_RUNTIME=server\nexport CLAUDE_MEM_SERVER_DATABASE_URL=postgres://...\nclaude-mem server api-key create","handlingStrategy":"validation","validationCode":"const runtime = (process.env.CLAUDE_MEM_RUNTIME ?? '').trim().toLowerCase();\nif (runtime && runtime !== 'server' && runtime !== 'server-beta') {\n  throw new Error(\n    `Refusing to run server commands with CLAUDE_MEM_RUNTIME=${runtime}; ` +\n    'set CLAUDE_MEM_RUNTIME=server or unset it',\n  );\n}","typeGuard":"function isServerRuntimeLiteral(v: string): boolean {\n  const t = v.trim().toLowerCase();\n  return t === '' || t === 'server' || t === 'server-beta';\n}","tryCatchPattern":null,"preventionTips":["Keep two distinct shell/env contexts: one for worker operation, one for server admin commands.","Scope CLAUDE_MEM_RUNTIME=worker to the specific worker processes instead of exporting it globally.","Note both 'server' and legacy 'server-beta' are accepted; anything else (including 'worker') blocks server subcommands."],"tags":["cli","configuration","env-var","runtime","server","worker"],"backgroundTag":"runtime-mode-mismatch","analyzedSha":"8bc631a71a487424b866756e43a6efa4574cc66b","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}