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

  1. Confirm the path exists and is a directory first: `await fs.stat(path)` or a `try { await fs.readdir(path) }` probe.
  2. Verify the path was created (e.g. by `mkdir -p`) before listing; create it if missing.
  3. Check you passed a directory, not a file path — list the parent directory instead or use the file API.
  4. If the path may vanish concurrently, catch this error and treat it as an empty/missing result rather than a hard failure.
  5. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/4513ef00470b7e92. Report an issue: GitHub.