thedotmack/claude-mem · critical

server startup configuration is invalid:

Error message

server startup configuration is invalid:

What it means

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.

Solutions

  1. Read the bulleted list in the error message — each line names exactly one env variable to fix.
  2. Set CLAUDE_MEM_SERVER_DATABASE_URL to a valid Postgres connection string (always required).
  3. In Docker: set CLAUDE_MEM_QUEUE_ENGINE=bullmq and CLAUDE_MEM_REDIS_URL to your Redis instance.
  4. 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.
  5. For local development outside Docker, keep local-dev auth/bypass settings but ensure the database URL is still provided.

Example fix

// before (docker-compose env, fails)
CLAUDE_MEM_RUNTIME=worker
CLAUDE_MEM_AUTH_MODE=local-dev
CLAUDE_MEM_QUEUE_ENGINE=
# after
CLAUDE_MEM_RUNTIME=server
CLAUDE_MEM_AUTH_MODE=api-key
CLAUDE_MEM_QUEUE_ENGINE=bullmq
CLAUDE_MEM_REDIS_URL=redis://redis:6379
CLAUDE_MEM_SERVER_DATABASE_URL=postgres://user:pass@db:5432/claude_mem
Defensive patterns

Strategy: validation

Validate before calling

const required = ['CLAUDE_MEM_SERVER_DATABASE_URL'];
const docker = process.env.DOCKER_BUILD != null || process.env.container != null; // container detection
if (docker) required.push('CLAUDE_MEM_QUEUE_ENGINE', 'CLAUDE_MEM_REDIS_URL');
const missing = required.filter(k => !(process.env[k] ?? '').trim());
if (missing.length) throw new Error(`missing server env: ${missing.join(', ')}`);
const rt = (process.env.CLAUDE_MEM_RUNTIME ?? '').trim();
if (docker && rt && rt !== 'server' && rt !== 'server-beta') throw new Error(`invalid CLAUDE_MEM_RUNTIME=${rt} in Docker`);

Try / catch

try {
  const service = await createServerService();
} catch (err) {
  if ((err as Error).message.startsWith('server startup configuration is invalid:')) {
    // print each '  - ' line as a separate ops remediation item and abort boot
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/4726436c87daf29e. Report an issue: GitHub.

Appendix: source

Thrown at src/server/runtime/create-server-service.ts:144

    }
  }

  const hasDatabaseUrl = Boolean((env.CLAUDE_MEM_SERVER_DATABASE_URL ?? '').trim());
  if (!hasDatabaseUrl) {
    errors.push('CLAUDE_MEM_SERVER_DATABASE_URL is required to start the server (Postgres connection string).');
  }

  const hasRedisUrl = Boolean((env.CLAUDE_MEM_REDIS_URL ?? '').trim());
  if (queueEngine === 'bullmq' && !hasRedisUrl) {
    errors.push('CLAUDE_MEM_REDIS_URL is required when CLAUDE_MEM_QUEUE_ENGINE=bullmq.');
  }

  if (errors.length > 0) {
    const message = [
      'server startup configuration is invalid:',
      ...errors.map(line => `  - ${line}`),
    ].join('\n');
    throw new Error(message);
  }

  return {
    isDocker,
    // Phase 1a: report the canonical `'server'` value when unset; legacy
    // `'server-beta'` is preserved verbatim when explicitly supplied so
    // diagnostics reflect the operator's actual config.
    runtime: runtime || 'server',
    authMode,
    queueEngine: queueEngine || 'disabled',
    hasDatabaseUrl,
    hasRedisUrl,
  };
}

// #2443 — the server runtime must load an observation mode before it can
// process any generation job; without it every job fails with "No mode
// loaded". We mirror the worker's pattern (src/services/worker-service.ts) and

View on GitHub (pinned to d8bc9755e7)