thedotmack/claude-mem · warning
Failed to parse files_modified JSON
Error message
Failed to parse files_modified JSON
What it means
extractRelevantFile tries to parse obs.files_modified as a JSON array to find a file directly under the target folder. If JSON.parse throws, this warning is logged and the function falls through to trying obs.files_read, ultimately returning the fallback label 'General'. The error is non-fatal by design.
Solutions
- Fix or regenerate the observation's files_modified value as a JSON array (JSON.stringify of string[])
- Set the field to NULL instead of an empty/invalid string when there are no modified files
- Re-run the summarize/import step so the observation is rewritten correctly
- Check writer code paths to ensure every persist site serializes with JSON.stringify
Example fix
// before obs.files_modified = ''; // after obs.files_modified = null; // or JSON.stringify([])
Defensive patterns
Strategy: validation
Validate before calling
let modified: string[] = [];
try { const p = JSON.parse(obs.files_modified); if (Array.isArray(p)) modified = p; } catch { /* fallback */ } Type guard
function asStringArray(v: unknown): string[] {
const p = typeof v === 'string' ? safeParse(v) : v;
return Array.isArray(p) ? p.filter((x): x is string => typeof x === 'string') : [];
} Try / catch
try { files = JSON.parse(obs.files_modified); } catch {
logger.warn('...', { raw: obs.files_modified?.slice(0, 100) });
files = [];
} Prevention
- Serialize with JSON.stringify at every write site
- Keep empty arrays as '[]' rather than empty strings
- Validate rows after import/migration
- Version-stamp observation rows so format changes are detectable
When it happens
Trigger: The observation's files_modified column contains invalid JSON — a raw comma-separated path list, an empty string that is not null, quoted-but-unterminated JSON, or binary/garbage data from a corrupt row.
Common situations: Rows written by older claude-mem versions with a different serialization; DB corruption or interrupted writes; observations created manually or by third-party tooling that wrote a plain string.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse files_read JSON
- Expected JSON array in observation list field, using plain…
- Failed to parse files JSON in hasDirectChildFile
- [SETTINGS] Failed to load settings, using defaults:
- sync hub status: response is not JSON
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/361275cdf2ccf331.
Report an issue: GitHub.
Appendix: source
Thrown at src/cli/claude-md-commands.ts:167
const likePattern = `%"${normalizedFolderPath}/%`;
const allMatches = db.prepare(sql).all(project, likePattern, likePattern, queryLimit) as ObservationRow[];
return allMatches.filter(obs => hasDirectChildFile(obs, relativeFolderPath)).slice(0, limit);
}
function extractRelevantFile(obs: ObservationRow, relativeFolder: string): string {
if (obs.files_modified) {
try {
const modified = JSON.parse(obs.files_modified);
if (Array.isArray(modified)) {
for (const file of modified) {
if (isDirectChild(file, relativeFolder)) {
return path.basename(file);
}
}
}
} catch (error) {
logger.warn('CLAUDE_MD', 'Failed to parse files_modified JSON', { error: error instanceof Error ? error.message : String(error) });
}
}
if (obs.files_read) {
try {
const read = JSON.parse(obs.files_read);
if (Array.isArray(read)) {
for (const file of read) {
if (isDirectChild(file, relativeFolder)) {
return path.basename(file);
}
}
}
} catch (error) {
logger.warn('CLAUDE_MD', 'Failed to parse files_read JSON', { error: error instanceof Error ? error.message : String(error) });
}
}
View on GitHub (pinned to d8bc9755e7)