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

  1. 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).
  2. If the data is recoverable manually, fix the JSON syntax, then re-run the operation.
  3. If the data is expendable, replace the file with '{}' so modifyJson treats it as a fresh store (you lose existing tasks/tags).
  4. 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

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


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/9cb442bc5fec70a7. Report an issue: GitHub.