thedotmack/claude-mem · error

Invalid transcript watch config

Error message

Invalid transcript watch config: ${resolvedPath}

What it means

After reading and JSON-parsing the watch config, loadTranscriptWatchConfig validates its shape: a truthy version and a watches object/array are required. A file that parses as JSON but lacks these fields is rejected as structurally invalid, with the resolved path in the message.

Solutions

  1. Add the required fields: "version": 1 and a "watches" section to the config file.
  2. Compare against the current documented schema and migrate an old-format config.
  3. Validate the JSON keys (version, watches, stateFile) after editing.
  4. Regenerate a fresh default config and re-apply your custom watches.

Example fix

// before
{ "stateFile": "~/.claude-mem/watch-state.json" }
// after
{ "version": 1, "watches": [{ "path": "~/.claude/projects/**/transcript.jsonl" }], "stateFile": "~/.claude-mem/watch-state.json" }
Defensive patterns

Strategy: validation

Validate before calling

const raw = JSON.parse(readFileSync(p, 'utf8'));
if (typeof raw.version !== 'number' || !raw.watches) throw new Error(`Invalid watch config at ${p}`);

Type guard

function isValidWatchConfig(v: unknown): v is TranscriptWatchConfig {
  return typeof v === 'object' && v !== null && 'version' in v && 'watches' in v;
}

Try / catch

try { const cfg = loadTranscriptWatchConfig(); } catch (e) { if (e.message.includes('Invalid transcript watch config')) { migrateOrRegenerateConfig(); } }

Prevention

When it happens

Trigger: The config file at resolvedPath exists and is valid JSON but omits version or watches — e.g. an empty object {}, an outdated schema, or a file containing only stateFile.

Common situations: Hand-edited config missing required keys; config created by an older plugin version before schema changes; partial write/truncation that still left valid JSON; copying a template but not filling it in.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/services/transcripts/config.ts:73

export function expandHomePath(inputPath: string): string {
  if (!inputPath) return inputPath;
  // Shared expandTilde/expandHome leave `~user/...` alone (resolving another
  // user's home is out of scope). The old inline version sliced one character
  // off any leading tilde, so `~alice/transcripts` was rewritten to
  // `<home>/alice/transcripts` and the watcher ingested nothing silently.
  return expandTilde(inputPath);
}

export function loadTranscriptWatchConfig(path = DEFAULT_CONFIG_PATH): TranscriptWatchConfig {
  const resolvedPath = expandHomePath(path);
  if (!existsSync(resolvedPath)) {
    throw new Error(`Transcript watch config not found: ${resolvedPath}`);
  }
  const raw = readFileSync(resolvedPath, 'utf-8');
  const parsed = JSON.parse(raw) as TranscriptWatchConfig;
  if (!parsed.version || !parsed.watches) {
    throw new Error(`Invalid transcript watch config: ${resolvedPath}`);
  }
  if (!parsed.stateFile) {
    parsed.stateFile = DEFAULT_STATE_PATH;
  }
  return parsed;
}

export function writeSampleConfig(path = DEFAULT_CONFIG_PATH): void {
  const resolvedPath = expandHomePath(path);
  const dir = dirname(resolvedPath);
  if (!existsSync(dir)) {
    mkdirSync(dir, { recursive: true });
  }
  writeFileSync(resolvedPath, JSON.stringify(SAMPLE_CONFIG, null, 2));
}

View on GitHub (pinned to d8bc9755e7)