thedotmack/claude-mem · warning

Transcript path missing or file does not exist: ${transcript

Error message

Transcript path missing or file does not exist: ${transcriptPath}

What it means

extractLastMessage validates the transcript path first: if it is empty/falsy or existsSync reports false, it warns and returns '' instead of throwing. Callers receive an empty string, which downstream typically means 'nothing to ingest' for that hook event.

Source

Thrown at src/shared/transcript-parser.ts:11

import { readFileSync, existsSync } from 'fs';
import { logger } from '../utils/logger.js';
import { SYSTEM_REMINDER_REGEX } from '../utils/tag-stripping.js';

export function extractLastMessage(
  transcriptPath: string,
  role: 'user' | 'assistant',
  stripSystemReminders: boolean = false
): string {
  if (!transcriptPath || !existsSync(transcriptPath)) {
    logger.warn('PARSER', `Transcript path missing or file does not exist: ${transcriptPath}`);
    return '';
  }

  const content = readFileSync(transcriptPath, 'utf-8').trim();
  if (!content) {
    logger.warn('PARSER', `Transcript file exists but is empty: ${transcriptPath}`);
    return '';
  }

  return extractLastMessageFromJsonl(content, role, stripSystemReminders);
}

/**
 * Extract last message from a JSONL transcript.
 *
 * Supports two field conventions for the per-line role marker:
 * - Claude Code:  `{"type":"assistant",...}`
 * - Cursor:       `{"role":"assistant",...}`

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Inspect the hook's JSON input to verify the transcript_path actually passed in.
  2. If the file was rotated or deleted, start a fresh session so Claude Code writes a new transcript.
  3. Disable or reschedule any cleanup that deletes ~/.claude/projects transcripts while claude-mem runs.

Example fix

// before
const content = readFileSync(transcriptPath, 'utf-8'); // throws ENOENT

// after
if (!transcriptPath || !existsSync(transcriptPath)) {
  logger.warn('PARSER', `Transcript path missing or file does not exist: ${transcriptPath}`);
  return '';
}
Defensive patterns

Strategy: validation

Validate before calling

if (!transcriptPath || !existsSync(transcriptPath)) {
  // skip this hook event rather than parsing a missing file
  return '';
}

Type guard

import { existsSync } from 'fs';
const isReadableTranscript = (p?: string | null): p is string =>
  typeof p === 'string' && p.length > 0 && existsSync(p);

Prevention

When it happens

Trigger: A hook calls extractLastMessage(transcriptPath, role) with an empty string, or the JSONL transcript under ~/.claude/projects was deleted/moved between session start and the hook read.

Common situations: Session resume referencing a pruned transcript; transcript-cleanup utilities running concurrently; hook config passing a malformed or wrong-machine path.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20). Data as JSON: /api/errors/4da36481e7e58c18. Report an issue: GitHub.