{"record":{"id":"6affa0f5dfa3329c","repo":"eyaltoledano/claude-task-master","slug":"invalid-json-in-file-filepath-error-message","errorCode":null,"errorMessage":"Invalid JSON in file ${filePath}: ${error.message}","messagePattern":"Invalid JSON in file (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tm-core/src/modules/storage/adapters/file-storage/file-operations.ts","lineNumber":63,"sourceCode":"\t\t\twriter = new Writer(filePath);\n\t\t\tthis.writers.set(filePath, writer);\n\t\t}\n\t\treturn writer;\n\t}\n\n\t/**\n\t * Read and parse JSON file\n\t */\n\tasync readJson(filePath: string): Promise<any> {\n\t\ttry {\n\t\t\tconst content = await fs.readFile(filePath, 'utf-8');\n\t\t\treturn JSON.parse(content);\n\t\t} catch (error: any) {\n\t\t\tif (error.code === 'ENOENT') {\n\t\t\t\tthrow error; // Re-throw ENOENT for caller to handle\n\t\t\t}\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\tthrow new Error(`Invalid JSON in file ${filePath}: ${error.message}`);\n\t\t\t}\n\t\t\tthrow new Error(`Failed to read file ${filePath}: ${error.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Write JSON file with atomic operation and cross-process locking.\n\t * Uses steno for atomic writes and proper-lockfile for cross-process safety.\n\t * WARNING: This replaces the entire file. For concurrent modifications,\n\t * use modifyJson() instead to prevent lost updates.\n\t */\n\tasync writeJson(\n\t\tfilePath: string,\n\t\tdata: FileStorageData | any\n\t): Promise<void> {\n\t\t// Ensure file exists for locking (proper-lockfile requires this)\n\t\tawait this.ensureFileExists(filePath);\n","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/modules/storage/adapters/file-storage/file-operations.ts#L45-L81","documentation":"readJson() parses a file with JSON.parse; when parsing fails with a SyntaxError the file exists but is not valid JSON, so a descriptive Error naming the file and parse message is thrown. ENOENT is deliberately re-thrown so callers can treat a missing file as 'no data' rather than corruption.","triggerScenarios":"Calling readJson (directly or via data/rawData/stateData accessors) on a file whose contents are truncated, hand-edited incorrectly, contain trailing commas/comments, or were written by another tool in a non-JSON format.","commonSituations":"A crashed or interrupted write left a partial file (outside this library's atomic steno writes); a user manually edited .taskmaster/tasks.json and broke syntax; merge conflict markers (<<<<<<<) left in the file; the file was saved with BOM or as YAML/JSON5.","solutions":["Open the file at the path in the message and fix the JSON syntax indicated by the parse error (line/column in error.message).","If the file is unimportant or regenerable, restore it from git (git checkout -- <file>) or delete it so the storage layer recreates it.","Validate the file with a parser (node -e \"JSON.parse(require('fs').readFileSync('<path>','utf8'))\") after editing to confirm it parses.","Avoid hand-editing storage files while the app runs; use the CLI commands that go through modifyJson/writeJson atomic writes."],"exampleFix":"// before (tasks.json contains a trailing comma)\n{ \"tasks\": [ ... ], }\n// after\n{\n  \"tasks\": [ ... ]\n}","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'fs';\nexport function isValidJsonFile(filePath: string): boolean {\n  try { JSON.parse(readFileSync(filePath, 'utf-8')); return true; }\n  catch (err: any) { return err.code === 'ENOENT'; } // missing is OK, malformed is not\n}","typeGuard":null,"tryCatchPattern":"try {\n  const data = await fileOps.readJson(filePath);\n} catch (err: any) {\n  if (err.code === 'ENOENT') return defaultValue;\n  if (err.message.startsWith('Invalid JSON in file')) {\n    // offer backup restore or interactive repair\n    return recoverFromBackup(filePath) ?? defaultValue;\n  }\n  throw err;\n}","preventionTips":["Never hand-edit storage JSON while the app is running; use CLI commands with atomic writes.","Validate edited files with a JSON linter/formatter before saving.","Keep storage files in git so corruption is recoverable via checkout.","Resolve git merge conflicts in .taskmaster files before running commands."],"tags":["json","file-storage","parse-error","corruption"],"backgroundTag":"invalid-json-file","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}