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
- Inspect the hook's JSON input to verify the transcript_path actually passed in.
- If the file was rotated or deleted, start a fresh session so Claude Code writes a new transcript.
- 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
- Validate transcript_path from hook JSON input before invoking the parser.
- Don't run transcript-cleanup jobs against ~/.claude/projects while sessions are active.
- Treat empty-string returns as 'skip event', not as data.
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
- Transcript file exists but is empty: ${transcriptPath}
- Mode file not found: ${modeId}.json (searched: ${this.modeDi
- MCP server script not found
- Generator paused for ${abortCategory}; preserving buffered w
- Invalid mode inheritance: ${modeId}. Only one level of inher
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/4da36481e7e58c18.
Report an issue: GitHub.