mastra-ai/mastra · error
Directory not found: ${path}
Error message
Directory not found: ${path} What it means
The recursive branch of `readdir` runs `test -d <dir> && find <dir> -mindepth 1 ...`. If that composite command exits non-zero — most commonly because `test -d` fails, i.e. the path is not an existing directory — the method throws this error. Note the implementation funnels any non-zero exit (including unexpected find errors, which are hidden by `2>/dev/null`) into this single 'Directory not found' message.
Source
Thrown at mastracode/sdk/src/agents/sandbox-filesystem.ts:432
return;
}
const result = await this.exec(`rmdir ${shellQuote(abs)}`);
if (result.exitCode !== 0 && !options?.force) {
throw new Error(`Directory not empty or not found: ${path}`);
}
}
async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {
const abs = await this.resolveAsync(path);
await this.assertContainedRealpath(abs, path);
if (options?.recursive) {
// Recursive listing emitting "type\tpath". `find -printf` is GNU-only
// (fails on macOS/BSD hosts backing a local sandbox), so classify each
// entry with a portable shell loop instead.
const result = await this.exec(
`test -d ${shellQuote(abs)} && find ${shellQuote(abs)} -mindepth 1 ${options.maxDepth ? `-maxdepth ${Number(options.maxDepth)} ` : ''}2>/dev/null | while IFS= read -r f; do if [ -d "$f" ]; then printf 'd\\t%s\\n' "$f"; else printf 'f\\t%s\\n' "$f"; fi; done`,
);
if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);
return this.parseFindOutput(result.stdout, abs, options);
}
// Non-recursive: list with name + type via a portable loop. Use printf,
// not echo — bash-as-/bin/sh (macOS local sandboxes) does not expand \t
// in echo arguments.
const result = await this.exec(
`cd ${shellQuote(abs)} 2>/dev/null && for f in * .[!.]*; do [ -e "$f" ] || continue; if [ -d "$f" ]; then printf 'd\\t%s\\n' "$f"; else printf 'f\\t%s\\n' "$f"; fi; done`,
);
if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);
return this.parseListOutput(result.stdout, options);
}
private parseListOutput(stdout: string, options?: ListOptions): FileEntry[] {
const entries: FileEntry[] = [];
for (const line of stdout.split('\n')) {
if (!line) continue;
const tab = line.indexOf('\t');
if (tab < 0) continue;View on GitHub (pinned to 75dd419e61)
Solutions
- Confirm the path exists and is a directory first: `await fs.stat(path)` or a `try { await fs.readdir(path) }` probe.
- Verify the path was created (e.g. by `mkdir -p`) before listing; create it if missing.
- Check you passed a directory, not a file path — list the parent directory instead or use the file API.
- If the path may vanish concurrently, catch this error and treat it as an empty/missing result rather than a hard failure.
- Inspect sandbox containment: a path outside allowed roots will fail resolution/assertion before this point; use paths inside the workspace.
Example fix
// before
const files = await sandboxFs.readdir('./src/generated', { recursive: true });
// after
if (await sandboxFs.exists('./src/generated')) {
const files = await sandboxFs.readdir('./src/generated', { recursive: true });
} else {
const files = [];
} Defensive patterns
Strategy: validation
Validate before calling
const stat = await sandboxFs.stat(dir).catch(() => null);
if (!stat || stat.type !== 'directory') throw new Error(`refusing readdir: ${dir} is not a directory`); Type guard
function isDirectoryEntry(e: FileEntry | undefined): e is FileEntry & { type: 'directory' } {
return e?.type === 'directory';
} Try / catch
try {
entries = await sandboxFs.readdir(dir, { recursive: true });
} catch (err) {
if (err instanceof Error && err.message === `Directory not found: ${dir}`) {
entries = [];
} else {
throw err;
}
} Prevention
- Stat the directory before recursive listing
- Create expected directories with `mkdir` (recursive by default) at session start
- Treat optional directories (generated output, plugins) as possibly absent
- Remember the message also covers non-ENOENT find failures — don't over-infer the cause
When it happens
Trigger: Calling `readdir(path, { recursive: true })` (directly or through the `entries` helper) on a path that does not exist, is a file, or is a symlink to a missing target; also when the recursive `find` pipeline fails for any other reason (e.g. `find` unavailable, broken pipe).
Common situations: Listing a project directory before scaffolding created it; a deleted/renamed working directory referenced by stale agent state; passing a file path where a directory was expected; macOS/BSD hosts where path resolution or find behaves differently than Linux.
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/4513ef00470b7e92.
Report an issue: GitHub.