mastra-ai/mastra · error · FileNotFoundError
FileNotFoundError: ${path}
Error message
FileNotFoundError: ${path} What it means
readFile() runs a shell probe in the sandbox that classifies the target before reading: directories exit with EXIT_IS_DIRECTORY and non-existent paths exit with EXIT_NOT_FOUND, so the sandbox throws FileNotFoundError(path) instead of attempting a base64 read. This gives callers a typed, distinguishable signal that the requested path does not exist inside the sandbox workspace (after symlink-containment checks passed).
Source
Thrown at mastracode/sdk/src/agents/sandbox-filesystem.ts:256
const result = await this.exec(script);
if (result.exitCode !== 0) {
throw new Error(`${context} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`);
}
return result;
}
// ── File operations ────────────────────────────────────────────────────
async readFile(path: string, options?: ReadOptions): Promise<string | Buffer> {
const abs = await this.resolveAsync(path);
await this.assertContainedRealpath(abs, path);
// Guard clauses first: redirecting from a directory "succeeds" with empty
// output on some shells, so classify before reading.
const result = await this.exec(
`if [ -d ${shellQuote(abs)} ]; then exit ${EXIT_IS_DIRECTORY}; elif [ ! -e ${shellQuote(abs)} ]; then exit ${EXIT_NOT_FOUND}; fi; base64 < ${shellQuote(abs)}`,
);
if (result.exitCode === EXIT_IS_DIRECTORY) throw new IsDirectoryError(path);
if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(path);
if (result.exitCode !== 0) {
throw new Error(`readFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
}
const buffer = Buffer.from(result.stdout.replace(/\s/g, ''), 'base64');
if (options?.encoding) {
return buffer.toString(options.encoding);
}
return buffer;
}
async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {
const abs = await this.resolveAsync(path);
await this.assertContainedDest(abs, path);
const b64 = toBuffer(content).toString('base64');
const dir = posixPath.dirname(abs);
const mkdir = options?.recursive === false ? '' : `mkdir -p ${shellQuote(dir)} && `;
if (options?.overwrite === false) {
// `set -C` (noclobber) makes the redirect itself the exclusivity check —View on GitHub (pinned to 75dd419e61)
Solutions
- Check the file exists (or create it) before reading: verify the producing step (writeFile/copyFile) ran first.
- Print/verify the exact path being passed and how it resolves relative to the sandbox basePath — remove leading host-absolute segments if the file lives inside the workdir.
- Use the force/idempotent pattern on the write side (or copyFile) to ensure the file is present before read.
- Wrap in try/catch on FileNotFoundError and treat as an expected 'missing' outcome rather than a crash.
Example fix
// before\nconst content = await sandbox.fs.readFile('output/result.json');\n// after\nlet content: string;\ntry {\n content = await sandbox.fs.readFile('output/result.json', { encoding: 'utf8' });\n} catch (e) {\n if (e instanceof FileNotFoundError) content = '';\n else throw e;\n} Defensive patterns
Strategy: try-catch
Validate before calling
let exists = false;\ntry {\n await fs.readFile(path);\n exists = true;\n} catch { /* probe read */ } Type guard
function isFileNotFoundError(e: unknown): e is FileNotFoundError {\n return e instanceof FileNotFoundError;\n} Try / catch
try {\n const content = await fs.readFile(path);\n} catch (e) {\n if (e instanceof FileNotFoundError) {\n // handle missing file: default value or early return\n } else {\n throw e;\n }\n} Prevention
- Ensure the producing step completed before reading outputs.
- Use workspace-relative paths consistently; never assume host-absolute paths map into the sandbox.
- Check path casing on Linux sandboxes.
- Prefer reading only after writeFile/copyFile of the same path succeeded.
When it happens
Trigger: Calling sandbox.files.readFile(path) when the file does not exist at the resolved workspace-relative path: a typo'd path, reading a file that was deleted or never written, reading a path that only exists on the host but not in the sandbox workdir, or a case-sensitivity mismatch (Linux sandbox vs macOS host).
Common situations: Agents reading generated output before the producing step ran; stale cache of previously-existing files; tests asserting on fixture files not copied into the sandbox workdir; referencing absolute host paths that get resolved inside the sandbox where they don't exist.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- pull-failed
- Sandbox workspace root resolution returned an empty path
- Path escapes workspace root: ${inputPath}
- Unable to verify path stays within workspace root: ${inputPa
- ${context} failed (exit ${result.exitCode}): ${result.stderr
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/df01cd4400101584.
Report an issue: GitHub.