eyaltoledano/claude-task-master · error · Error
Failed to read ${filePath} for modification: ${err.message}
Error message
Failed to read ${filePath} for modification: ${err.message} What it means
modifyJson() re-reads the target file inside the cross-process lock; if the read fails with anything other than ENOENT or a SyntaxError (i.e. a permission or I/O error), it throws 'Failed to read <path> for modification: <reason>'. The modification is intentionally aborted before applying the modifier so a broken read can never cause a lost update.
Source
Thrown at packages/tm-core/src/modules/storage/adapters/file-storage/file-operations.ts:151
} 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);
} finally {
if (release) {
try {
await release();
} catch (err: any) {
// Log but don't throw - lock may have been released alreadyView on GitHub (pinned to c0c98d367c)
Solutions
- Read the OS error in the message (EACCES/EISDIR/etc.) and correct it — grant read permission or remove a directory that replaced the file.
- Verify the path passed to the storage layer is the intended file, not a directory or symlink to an unreadable target.
- If in a container, ensure the volume mount is healthy and owned by the process user (match UID/GID).
- Retry the operation after resolving the transient I/O condition; the cross-process lock was already released.
Example fix
// before
ls -ld .taskmaster/tasks.json # drwxr-xr-x (a directory!)
// after
rm -rf .taskmaster/tasks.json && echo '{}' > .taskmaster/tasks.json Defensive patterns
Strategy: try-catch
Validate before calling
import { access, constants, stat } from 'fs/promises';
export async function isModifiableFile(filePath: string): Promise<boolean> {
try {
const s = await stat(filePath);
if (!s.isFile()) return false;
await access(filePath, constants.R_OK | constants.W_OK);
return true;
} catch { return false; }
} Try / catch
try {
await fileOps.modifyJson(filePath, (data) => mutate(data));
} catch (err: any) {
if (err.message.includes('for modification')) {
console.error(`Fix filesystem issue on ${filePath}: ${err.message}`);
throw err; // do not proceed — modification was aborted to avoid lost updates
}
throw err;
} Prevention
- Keep permissions stable on .taskmaster files (don't chown to root in shared environments).
- Mount volumes with correct UID/GID ownership in containers.
- Preflight stat+access checks before batch tag operations.
- Replace stale lock targets that were swapped for directories or symlinks.
When it happens
Trigger: saveTasks, createTag, deleteTag, renameTag, or any modifyJson call where fs.readFile fails with EACCES, EISDIR, EIO, EBUSY, or a similar OS-level error on the lock target file.
Common situations: Permissions changed on .taskmaster files between reads and writes (e.g. chown by another user); the file was replaced by a directory; filesystem errors in Docker/NFS mounts; antivirus or backup tools holding the file on Windows.
Related errors
- Failed to read file ${filePath}: ${error.message}
- Failed to create directory ${dirPath}: ${error.message}
- Failed to delete file ${filePath}: ${error.message}
- Failed to copy file from ${srcPath} to ${destPath}: ${error.
- Could not create directory for ${pathType}: ${parentDir}. Er
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/da5a82533730a6bd.
Report an issue: GitHub.