{"record":{"id":"5c8ade3ba1dff233","repo":"thedotmack/claude-mem","slug":"failed-to-parse-files-json-in-hasdirectchildfile","errorCode":null,"errorMessage":"Failed to parse files JSON in hasDirectChildFile","messagePattern":"Failed to parse files JSON in hasDirectChildFile","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/cli/claude-md-commands.ts","lineNumber":128,"sourceCode":"      const fullPath = path.join(dir, entry.name);\n      folders.add(fullPath);\n      walkDirectoriesWithIgnore(fullPath, folders, depth + 1);\n    }\n  } catch {\n    // Ignore permission errors\n  }\n}\n\nfunction hasDirectChildFile(obs: ObservationRow, folderPath: string): boolean {\n  const checkFiles = (filesJson: string | null): boolean => {\n    if (!filesJson) return false;\n    try {\n      const files = JSON.parse(filesJson);\n      if (Array.isArray(files)) {\n        return files.some(f => isDirectChild(f, folderPath));\n      }\n    } catch (error) {\n      logger.warn('CLAUDE_MD', 'Failed to parse files JSON in hasDirectChildFile', { error: error instanceof Error ? error.message : String(error) });\n    }\n    return false;\n  };\n\n  return checkFiles(obs.files_modified) || checkFiles(obs.files_read);\n}\n\nfunction findObservationsByFolder(db: Database, relativeFolderPath: string, project: string, limit: number): ObservationRow[] {\n  const queryLimit = limit * 3;\n\n  const sql = `\n    SELECT o.*, o.discovery_tokens\n    FROM observations o\n    WHERE o.project = ?\n      AND (o.files_modified LIKE ? OR o.files_read LIKE ?)\n    ORDER BY o.created_at_epoch DESC\n    LIMIT ?\n  `;","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/cli/claude-md-commands.ts#L110-L146","documentation":"hasDirectChildFile parses a JSON array of file paths stored in an observation (files_modified or files_read) and checks whether any is a direct child of a folder. When the stored string is not valid JSON, JSON.parse throws inside checkFiles and this warning is logged; the function safely returns false, meaning the folder is treated as having no direct-child files.","triggerScenarios":"Calling hasDirectChildFile with an observation whose files_modified or files_read field is malformed — e.g. a bare path string instead of a JSON array ('src/foo.ts' rather than '[\"src/foo.ts\"]'), truncated JSON, single quotes, or non-JSON text written by an older/buggy writer version.","commonSituations":"Legacy database rows written before the JSON-array convention was adopted; manual edits to the claude-mem SQLite DB; partial writes from a crashed process leaving truncated JSON; data imported from another tool.","solutions":["Inspect the offending observation row (obs.files_modified / obs.files_read) and fix or re-write it as a proper JSON array of path strings","Delete or null out the malformed observation so it is skipped","Add a writer-side guard that always JSON.stringify the array before persisting","Migrate old rows with a one-time script that re-serializes or clears non-JSON values"],"exampleFix":"// before\nobs.files_modified = 'src/a.ts, src/b.ts';\n// after\nobs.files_modified = JSON.stringify(['src/a.ts', 'src/b.ts']);","handlingStrategy":"validation","validationCode":"function isPathArray(v) {\n  if (typeof v !== 'string') return false;\n  try { const p = JSON.parse(v); return Array.isArray(p) && p.every(x => typeof x === 'string'); }\n  catch { return false; }\n}\n// call hasDirectChildFile only when isPathArray(obs.files_modified)","typeGuard":"function isFilesJson(v: unknown): v is string { return typeof v === 'string' && v.trimStart().startsWith('['); }","tryCatchPattern":"try {\n  const files = JSON.parse(filesJson);\n  if (Array.isArray(files)) return files.some(f => isDirectChild(f, folderPath));\n} catch { return false; } // treat malformed as 'no match'","preventionTips":["Always JSON.stringify arrays before persisting observation fields","Store NULL, not '', when there are no files","Add a DB migration normalizing legacy non-JSON values","Log the raw value on parse failure to spot writer bugs early"],"tags":["json","parsing","data-integrity"],"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"}