thedotmack/claude-mem · error · Error

Invalid CLAUDE_MEM_WORKER_PORT in settings.json: ${rawPort}

Error message

Invalid CLAUDE_MEM_WORKER_PORT in settings.json: ${rawPort}

What it means

Thrown by parseWorkerPort() after the value passes the non-empty-string check but fails strict numeric validation. The check requires parseInt to yield an integer in the range 1–65535 AND that String(port) exactly equals the trimmed input — the latter rejects leading zeros, trailing characters, signed values, and non-canonical forms. This prevents silently coercing garbage like '8080abc' into port 8080.

Source

Thrown at scripts/export-memories.ts:26

import type {
  ObservationRecord,
  SdkSessionRecord,
  SessionSummaryRecord,
  UserPromptRecord,
  ExportData
} from './types/export.js';

const WORKER_FETCH_TIMEOUT_MS = 30_000;

function parseWorkerPort(rawPort: unknown): number {
  if (typeof rawPort !== 'string' || rawPort.trim() === '') {
    throw new Error('Invalid CLAUDE_MEM_WORKER_PORT in settings.json: missing');
  }

  const normalized = rawPort.trim();
  const port = Number.parseInt(normalized, 10);
  if (!Number.isInteger(port) || port < 1 || port > 65535 || String(port) !== normalized) {
    throw new Error(`Invalid CLAUDE_MEM_WORKER_PORT in settings.json: ${rawPort}`);
  }
  return port;
}

async function fetchWithTimeout(url: string, init?: RequestInit): Promise<Response> {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), WORKER_FETCH_TIMEOUT_MS);

  try {
    return await fetch(url, {
      ...init,
      signal: controller.signal,
    });
  } catch (error) {
    if (error instanceof Error && error.name === 'AbortError') {
      throw new Error(`Worker request timed out after ${WORKER_FETCH_TIMEOUT_MS}ms: ${url}`);
    }
    throw error;

View on GitHub (pinned to d768ba3643)

Solutions

  1. Open ~/.claude-mem/settings.json and correct CLAUDE_MEM_WORKER_PORT to a plain decimal string in 1–65535 (e.g. "44328") with no spaces, signs, or leading zeros.
  2. If the worker is running, read the actual port from the worker's startup log and copy that exact value.
  3. Delete the key and restart the worker so it rewrites a clean value, then retry the export.

Example fix

// before
{ "CLAUDE_MEM_WORKER_PORT": " 08080 " }
// after
{ "CLAUDE_MEM_WORKER_PORT": "8080" }
Defensive patterns

Strategy: validation

Validate before calling

function isValidPortLiteral(raw: unknown): raw is string {
  if (typeof raw !== 'string') return false;
  const n = raw.trim();
  if (!/^\d{1,5}$/.test(n)) return false;
  const p = Number(n);
  return p >= 1 && p <= 65535 && String(p) === n;
}

Type guard

function isWorkerPort(v: unknown): v is string {
  if (typeof v !== 'string') return false;
  const n = v.trim();
  if (!/^\d+$/.test(n)) return false;
  const p = Number.parseInt(n, 10);
  return Number.isInteger(p) && p >= 1 && p <= 65535 && String(p) === n;
}

Prevention

When it happens

Trigger: CLAUDE_MEM_WORKER_PORT is set to a value like '0', '99999', '-5', '8080abc', '08080', '0x1f90', '8080 ', '8.0', or any value where Number.parseInt disagrees with the canonical decimal string. The String(port) !== normalized clause specifically catches leading-zero and trailing-suffix cases that parseInt alone would tolerate.

Common situations: Someone edited settings.json and quoted a port with a typo or a trailing newline. A port copied from a URL that included a path (e.g. ':44328/api'). A value written by tooling that appended a unit or comment. Leading zeros from a zero-padded config generator.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/9c4007b92d538a2d. Report an issue: GitHub.