thedotmack/claude-mem · warning

Missing schema for watch

Error message

Missing schema for watch

What it means

When the transcript watcher sets up a watch target, resolveSchema() maps a string watch.schema to an entry in the config's top-level `schemas` map (an inline schema object is used as-is). If the string names a schema that does not exist in that map, the lookup returns null, this warning is logged, and the watch is skipped — no files are tailed for it.

Source

Thrown at src/services/transcripts/watcher.ts:116

      await this.setupWatch(watch);
    }
  }

  stop(): void {
    for (const tailer of this.tailers.values()) {
      tailer.close();
    }
    this.tailers.clear();
    for (const watcher of this.rootWatchers) {
      watcher.close();
    }
    this.rootWatchers = [];
  }

  private async setupWatch(watch: WatchTarget): Promise<void> {
    const schema = this.resolveSchema(watch);
    if (!schema) {
      logger.warn('TRANSCRIPT', 'Missing schema for watch', { watch: watch.name });
      return;
    }

    const resolvedPath = expandHomePath(watch.path);
    const files = this.resolveWatchFiles(resolvedPath);

    for (const filePath of files) {
      await this.addTailer(filePath, watch, schema);
    }

    const watchRoot = this.deepestNonGlobAncestor(resolvedPath);
    if (!watchRoot || !existsSync(watchRoot)) {
      logger.debug('TRANSCRIPT', 'Watch root does not exist, skipping fs.watch', { watch: watch.name, watchRoot });
      return;
    }

    try {
      const watcher = fsWatch(watchRoot, { recursive: true, persistent: true }, (event, name) => {

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Open the transcript watch config and check the exact keys under `schemas`; fix the watch's `schema` string to match one of them
  2. Or replace the string with an inline schema object on the watch itself
  3. After fixing, restart the worker so setupWatch runs again with the corrected config

Example fix

// before
{ "schemas": { "codex-v1": { ... } }, "watches": [ { "name": "codex", "schema": "codex", "path": "~/.codex/sessions/**/*.jsonl" } ] }

// after
{ "schemas": { "codex-v1": { ... } }, "watches": [ { "name": "codex", "schema": "codex-v1", "path": "~/.codex/sessions/**/*.jsonl" } ] }
Defensive patterns

Strategy: validation

Validate before calling

function assertWatchSchemasValid(config: TranscriptWatchConfig): void {
  for (const watch of config.watches) {
    if (typeof watch.schema === 'string' && !config.schemas?.[watch.schema]) {
      throw new Error(`watch '${watch.name}' references unknown schema '${watch.schema}'`);
    }
  }
}

Type guard

function hasResolvableSchema(watch: WatchTarget, schemas?: Record<string, TranscriptSchema>): boolean {
  if (typeof watch.schema === 'string') return Boolean(schemas?.[watch.schema]);
  return Boolean(watch.schema);
}

Prevention

When it happens

Trigger: A watch declares "schema": "codex" (or any name) that has no matching key under `schemas` in the same transcript watch config JSON; the schema was renamed or removed, or the name has a typo/case mismatch.

Common situations: Upgrading claude-mem versions where bundled schema names changed; hand-editing the watch config and misspelling the schema reference; splitting config files so the watch and its schema definition end up in different files.

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@e2d1df569a (2026-08-20). Data as JSON: /api/errors/c25b4ee6c80e2f12. Report an issue: GitHub.