mastra-ai/mastra · error · FileReadRequiredError
EREAD_REQUIRED
EREAD_REQUIRED
Error message
${reason} What it means
To keep the model's context accurate, a read-tracker records the last-read time of files. If a write tool targets a file whose content changed on disk after the agent last read it (or was never read), `readTracker.needsReRead` returns a reason and the tool throws `FileReadRequiredError` with that reason. This forces a fresh read before overwriting, preventing lost-update bugs.
Source
Thrown at packages/core/src/workspace/tools/tools.ts:297
enrichedContext = { ...enrichedContext, __expectedMtime: record.modifiedAtRead };
}
try {
const stat = await fs.stat(input.path);
// Policy gate: require the agent to have read the file first.
// Only evaluate when explicitly configured (opt-in policy).
// Safe default true = fail-closed if a dynamic function throws.
if (config.requireReadBeforeWrite !== undefined) {
const shouldRequireRead = await resolveDynamicValue(
config.requireReadBeforeWrite,
{ args: input, requestContext: enrichedContext.requestContext ?? {}, workspace: effectiveWorkspace },
true,
);
if (shouldRequireRead) {
const check = readTracker.needsReRead(input.path, stat.modifiedAt);
if (check.needsReRead) {
throw new FileReadRequiredError(input.path, check.reason!);
}
}
}
} catch (error) {
if (!(error instanceof FileNotFoundError)) {
throw error;
}
// Missing file: if a read record exists the expectedMtime is
// already attached, so downstream writeFile can treat this as
// stale. Otherwise it's a genuinely new file.
}
}
const result = await tool.execute(input, enrichedContext);
// Post-execution: track reads / clear write records
if (mode === 'read' && fs) {
try {View on GitHub (pinned to 75dd419e61)
Solutions
- Call the readFile tool on the path first, then retry the write so the tracker records a fresh read
- If the modification is expected/external, re-read and re-apply changes based on current content
- Structure agent workflows as read-then-write per file instead of blind writes
Example fix
// before
await writeFile({ path: 'config.ts', content: newContent }); // EREAD_REQUIRED
// after
const current = await readFile({ path: 'config.ts' });
await writeFile({ path: 'config.ts', content: merge(current, newContent) }); Defensive patterns
Strategy: retry
Try / catch
try {
return await writeTool.execute({ path, content }, ctx);
} catch (err) {
if (err?.code === 'EREAD_REQUIRED') {
const current = await readFileTool.execute({ path }, ctx);
return await writeTool.execute({ path, content: mergeWithCurrent(current, content) }, ctx);
}
throw err;
} Prevention
- Always read a file via the readFile tool before writing it in the same session
- Re-read files after any external modification (git ops, formatters, other agents)
- Design agent loops so write steps follow a fresh read rather than cached content from earlier turns
When it happens
Trigger: Calling a write/mutate tool on `input.path` where the file's `stat.modifiedAt` is newer than the tracked read time, or where the file was never read in this session (`needsReRead` true with a reason such as 'file not read' or 'modified since last read').
Common situations: External processes (linter/formatter, git checkout, another agent) modify a file between the agent's read and write; agent session resumes with stale read history; user edits a file while the agent works on it.
Related errors
- MastraFactory: integrations [${channelRegistrations.map(({ i
- Directory ${path.basename(targetPath)} already exists
- Directory already exists and is not empty: ${targetDir}
- A file or directory named "${projectName}" already exists. P
- Skipped: Scorer ${filename} already exists at ${scorersPath}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/6f8091e9ff8accaf.
Report an issue: GitHub.