{"record":{"id":"903a6e15a48e6788","repo":"thedotmack/claude-mem","slug":"failed-to-parse-files-read-json","errorCode":null,"errorMessage":"Failed to parse files_read JSON","messagePattern":"Failed to parse files_read JSON","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/cli/claude-md-commands.ts","lineNumber":182,"sourceCode":"        }\n      }\n    } catch (error) {\n      logger.warn('CLAUDE_MD', 'Failed to parse files_modified JSON', { error: error instanceof Error ? error.message : String(error) });\n    }\n  }\n\n  if (obs.files_read) {\n    try {\n      const read = JSON.parse(obs.files_read);\n      if (Array.isArray(read)) {\n        for (const file of read) {\n          if (isDirectChild(file, relativeFolder)) {\n            return path.basename(file);\n          }\n        }\n      }\n    } catch (error) {\n      logger.warn('CLAUDE_MD', 'Failed to parse files_read JSON', { error: error instanceof Error ? error.message : String(error) });\n    }\n  }\n\n  return 'General';\n}\n\nfunction formatObservationsForClaudeMd(observations: ObservationRow[], folderPath: string): string {\n  const lines: string[] = [];\n  lines.push('# Recent Activity');\n  lines.push('');\n  lines.push('<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->');\n  lines.push('');\n\n  if (observations.length === 0) {\n    lines.push('*No recent activity*');\n    return lines.join('\\n');\n  }\n","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/cli/claude-md-commands.ts#L164-L200","documentation":"The second parse attempt in extractRelevantFile: obs.files_read is parsed as a JSON array of paths to find a direct child of the folder. Invalid JSON triggers this warning and the function returns 'General' as the section label. Non-fatal; only the generated CLAUDE.md section naming degrades.","triggerScenarios":"obs.files_read holds malformed JSON — a plain path string, truncated array like '[\"src/a.ts\"', single-quoted entries, or non-string JSON (e.g. an object) that passes parse but not Array.isArray, leaving paths undefined downstream (though the warn itself fires only on throw).","commonSituations":"Historic rows predating the array format; corrupted DB rows after a crash; observations written by external scripts; manual DB edits.","solutions":["Rewrite files_read as a valid JSON array of path strings","Null the field when empty rather than storing '' or garbage","Regenerate the observation via the normal capture pipeline","Add a migration to normalize/blank legacy malformed values"],"exampleFix":"// before\nobs.files_read = '[\"src/a.ts\"';\n// after\nobs.files_read = '[\"src/a.ts\"]';","handlingStrategy":"validation","validationCode":"if (obs.files_read) {\n  try { const read = JSON.parse(obs.files_read); if (Array.isArray(read)) { /* use */ } } catch { /* use 'General' */ }\n}","typeGuard":"function isJsonArrayString(v: unknown): v is string { return typeof v === 'string' && v.trimStart().startsWith('['); }","tryCatchPattern":"try { read = JSON.parse(obs.files_read); } catch { read = []; } // default keeps flow to 'General'","preventionTips":["Never hand-edit observation JSON in the DB","Regenerate observations via the pipeline instead of patching rows","Guard writers so partial/truncated writes cannot persist","Add integration tests covering empty and legacy field values"],"tags":["json","parsing","fallback"],"backgroundTag":"json-parse-error","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}