mastra-ai/mastra · error
Directory not empty or not found: ${path}
Error message
Directory not empty or not found: ${path} What it means
`rmdir` on the sandbox filesystem removes a directory. Without `recursive: true` it shells out to the POSIX `rmdir` command, which only succeeds on an empty, existing directory. This error is thrown when the `rmdir` command exits non-zero and the call was not made with `force: true`, covering both the 'directory still has contents' and 'directory does not exist' failure modes (their stderr is collapsed into this single message).
Source
Thrown at mastracode/sdk/src/agents/sandbox-filesystem.ts:418
const abs = await this.resolveAsync(path);
await this.assertContainedDest(abs, path);
const flag = options?.recursive === false ? '' : '-p ';
await this.execOk(`mkdir ${flag}${shellQuote(abs)}`, `mkdir ${path}`);
}
async rmdir(path: string, options?: RemoveOptions): Promise<void> {
const abs = await this.resolveAsync(path);
// Same parent containment as deleteFile — `rm -r` through a symlinked
// parent would otherwise delete outside the workspace.
await this.assertContainedRealpath(posixPath.dirname(abs), path);
if (options?.recursive) {
const force = options?.force ? '-f ' : '';
await this.execOk(`rm -r ${force}${shellQuote(abs)}`, `rmdir ${path}`);
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 \tView on GitHub (pinned to 75dd419e61)
Solutions
- Pass `{ recursive: true }` to remove a non-empty directory tree: `fs.rmdir(path, { recursive: true })`.
- Pass `{ force: true }` if you want best-effort removal and don't care about failure (e.g. cleanup on shutdown).
- Verify the path exists and is a directory with `fs.stat(path)` or `fs.readdir(path)` before calling rmdir.
- Empty the directory first (iterate `readdir` and `deleteFile` each entry) if you intentionally want non-recursive removal but only when empty.
- Check for typos or stale references: the path may point outside the sandbox containment root or have been deleted already.
Example fix
// before
await sandboxFs.rmdir('./build/cache'); // throws if cache has files
// after
await sandboxFs.rmdir('./build/cache', { recursive: true, force: true }); Defensive patterns
Strategy: try-catch
Validate before calling
const stat = await sandboxFs.stat(path).catch(() => null); const canRmdir = stat?.type === 'directory' && (await sandboxFs.readdir(path)).length === 0;
Try / catch
try {
await sandboxFs.rmdir(path);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Directory not empty or not found')) {
await sandboxFs.rmdir(path, { recursive: true, force: true });
} else {
throw err;
}
} Prevention
- Default to `{ recursive: true }` unless empty-directory semantics are required
- Use `force: true` for idempotent cleanup paths (shutdown, teardown)
- `stat` the target to confirm it exists and is a directory before removal
- Never assume a directory is empty — agent tools and builds may have written into it
When it happens
Trigger: Calling `sandboxFs.rmdir(path)` (no options) when the target directory contains files or subdirectories; calling it on a path that does not exist; calling it on a path that resolves to a file rather than a directory. With `force: true` the error is suppressed.
Common situations: Trying to clean up a workspace directory that an agent or build step wrote files into; stale cleanup code after a rename that left the old directory populated or already deleted; a typo'd path that never existed; race conditions where another process removed the directory between existence check and rmdir.
Related errors
- Unable to verify path stays within workspace root: ${inputPa
- ${context} failed (exit ${result.exitCode}): ${result.stderr
- readFile ${path} failed (exit ${result.exitCode}): ${result.
- writeFile ${path} failed (exit ${result.exitCode}): ${result
- Invalid environment variable name: "${key}"
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/6a7b02a0cd8b821b.
Report an issue: GitHub.