eyaltoledano/claude-task-master · critical · Error
Corrupted JSON in ${filePath}: ${err.message}. File contains
Error message
Corrupted JSON in ${filePath}: ${err.message}. File contains: ${content.substring(0, 100)}... What it means
During modifyJson's locked read-modify-write, a SyntaxError from JSON.parse triggers a corruption check: if the file content is empty or '{}' it is treated as a fresh file, but any other unparseable content is real corruption and throws immediately rather than silently wiping data. This protects concurrent writers from clobbering a damaged-but-meaningful file.
Source
Thrown at packages/tm-core/src/modules/storage/adapters/file-storage/file-operations.ts:145
// Re-read file INSIDE lock to get current state
// This prevents lost updates from stale snapshots
let currentData: T;
try {
const content = await fs.readFile(filePath, 'utf-8');
currentData = JSON.parse(content);
} catch (err: any) {
// Distinguish between expected empty/new files and actual corruption
if (err.code === 'ENOENT') {
// File doesn't exist yet - start fresh
currentData = {} as T;
} else if (err instanceof SyntaxError) {
// Check if it's just an empty file (our ensureFileExists writes '{}')
const content = await fs.readFile(filePath, 'utf-8').catch(() => '');
if (content.trim() === '' || content.trim() === '{}') {
currentData = {} as T;
} else {
// Actual JSON corruption - this is a serious error
throw new Error(
`Corrupted JSON in ${filePath}: ${err.message}. File contains: ${content.substring(0, 100)}...`
);
}
} else {
// Other errors (permission, I/O) should be surfaced
throw new Error(
`Failed to read ${filePath} for modification: ${err.message}`
);
}
}
// Apply modification
const newData = await modifier(currentData);
// Write atomically using steno (same pattern as workflow-state-manager)
const content = JSON.stringify(newData, null, 2);
const writer = this.getWriter(filePath);
await writer.write(content);View on GitHub (pinned to c0c98d367c)
Solutions
- Inspect the file contents shown after 'File contains:' (first 100 chars) to identify the corruption, then repair or restore it (git checkout -- <file> or from backup).
- If the data is recoverable manually, fix the JSON syntax, then re-run the operation.
- If the data is expendable, replace the file with '{}' so modifyJson treats it as a fresh store (you lose existing tasks/tags).
- Prevent recurrence by only writing these files through the library's atomic writeJson/modifyJson APIs, not external editors or scripts.
Example fix
// before (tasks.json contains merge markers)
<<<<<<< HEAD
{ "tasks": [] }
=======
{ "tasks": [{ "id": 1 }] }
>>>>>>> feature
// after
git checkout -- .taskmaster/tasks.json # or resolve the merge and keep valid JSON Defensive patterns
Strategy: try-catch
Validate before calling
import { readFile } from 'fs/promises';
export async function isFileHealthy(filePath: string): Promise<boolean> {
try {
const c = (await readFile(filePath, 'utf-8')).trim();
return c === '' || c === '{}' || JSON.parse(c) !== undefined;
} catch { return false; }
} Try / catch
try {
await fileOps.modifyJson(filePath, (data) => mutate(data));
} catch (err: any) {
if (err.message.startsWith('Corrupted JSON in')) {
// do NOT auto-overwrite; prompt user or restore from backup/git
await restoreFromBackup(filePath);
return fileOps.modifyJson(filePath, (data) => mutate(data));
}
throw err;
} Prevention
- Write these files only through writeJson/modifyJson (atomic steno writes), never raw fs.writeFile or external scripts.
- Keep .taskmaster files committed/backed up so corruption is recoverable.
- Resolve merge conflicts before running task commands.
- Monitor disk-full conditions that cause truncated writes from other tools.
When it happens
Trigger: Any modifyJson consumer (saveTasks, createTag, deleteTag, renameTag, writes, modifyJSON) invoked on an existing .taskmaster JSON file whose content is neither valid JSON nor empty/'{}' — e.g. partial writes from external tools, merge-conflict markers, binary garbage.
Common situations: A previous non-atomic write (another tool or an older library version) crashed mid-write; a git merge left conflict markers in tasks.json; disk filled during a write leaving a truncated file; user edited the file with mismatched braces.
Related errors
- Invalid JSON in file ${filePath}: ${error.message}
- Failed to parse JSON response: ${parseError.message}. Respon
- CONFIG_ERROR
- Failed to read file ${filePath}: ${error.message}
- Failed to read ${filePath} for modification: ${err.message}
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/9cb442bc5fec70a7.
Report an issue: GitHub.