{"record":{"id":"4513ef00470b7e92","repo":"mastra-ai/mastra","slug":"directory-not-found-path","errorCode":null,"errorMessage":"Directory not found: ${path}","messagePattern":"Directory not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/agents/sandbox-filesystem.ts","lineNumber":432,"sourceCode":"      return;\n    }\n    const result = await this.exec(`rmdir ${shellQuote(abs)}`);\n    if (result.exitCode !== 0 && !options?.force) {\n      throw new Error(`Directory not empty or not found: ${path}`);\n    }\n  }\n\n  async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {\n    const abs = await this.resolveAsync(path);\n    await this.assertContainedRealpath(abs, path);\n    if (options?.recursive) {\n      // Recursive listing emitting \"type\\tpath\". `find -printf` is GNU-only\n      // (fails on macOS/BSD hosts backing a local sandbox), so classify each\n      // entry with a portable shell loop instead.\n      const result = await this.exec(\n        `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`,\n      );\n      if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);\n      return this.parseFindOutput(result.stdout, abs, options);\n    }\n    // Non-recursive: list with name + type via a portable loop. Use printf,\n    // not echo — bash-as-/bin/sh (macOS local sandboxes) does not expand \\t\n    // in echo arguments.\n    const result = await this.exec(\n      `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`,\n    );\n    if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);\n    return this.parseListOutput(result.stdout, options);\n  }\n\n  private parseListOutput(stdout: string, options?: ListOptions): FileEntry[] {\n    const entries: FileEntry[] = [];\n    for (const line of stdout.split('\\n')) {\n      if (!line) continue;\n      const tab = line.indexOf('\\t');\n      if (tab < 0) continue;","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/agents/sandbox-filesystem.ts#L414-L450","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nconst files = await sandboxFs.readdir('./src/generated', { recursive: true });\n// after\nif (await sandboxFs.exists('./src/generated')) {\n  const files = await sandboxFs.readdir('./src/generated', { recursive: true });\n} else {\n  const files = [];\n}","handlingStrategy":"validation","validationCode":"const stat = await sandboxFs.stat(dir).catch(() => null);\nif (!stat || stat.type !== 'directory') throw new Error(`refusing readdir: ${dir} is not a directory`);","typeGuard":"function isDirectoryEntry(e: FileEntry | undefined): e is FileEntry & { type: 'directory' } {\n  return e?.type === 'directory';\n}","tryCatchPattern":"try {\n  entries = await sandboxFs.readdir(dir, { recursive: true });\n} catch (err) {\n  if (err instanceof Error && err.message === `Directory not found: ${dir}`) {\n    entries = [];\n  } else {\n    throw err;\n  }\n}","preventionTips":["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"],"tags":["filesystem","sandbox","readdir"],"backgroundTag":"directory-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}