vercel/ai · error

File not found

Error message

File not found: ${inputPath}

What it means

Thrown by readFile when the path resolved and passed the existence check, but the sandbox's readTextFile returned null/undefined — meaning the file could not actually be read as text (e.g. it is a directory, a binary file, or was removed between the check and the read). The library reports it as 'File not found' with the caller's original input path.

Solutions

  1. Check that the path targets a regular file, not a directory (use ops.ls or ops.bash with `test -f`).
  2. For binary content, do not use readFile — copy or inspect the file via ops.bash commands instead.
  3. Retry the read once if the file was concurrently modified; otherwise re-list the directory to find the correct file name.
  4. Verify sandbox file permissions allow the session user to read the file.

Example fix

// before: reading a directory
const content = await ops.readFile('src'); // File not found: src

// after: only read regular files
const entries = await ops.ls('src');
const content = await ops.readFile(`src/${entries[0]}`);
Defensive patterns

Strategy: try-catch

Validate before calling

async function isRegularTextFile(ops, p) {
  const r = await ops.bash(`test -f ${JSON.stringify(p)} && echo file || echo notfile`);
  return r.output.includes('file');
}

Try / catch

try {
  return await ops.readFile(path);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('File not found:')) {
    const parent = path.posix.dirname(path);
    const entries = await ops.ls(parent); // discover the real name
    return ops.readFile(`${parent}/${entries.find(x => x === path.posix.basename(path)) ?? entries[0]}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: readFile('notes/') where the path points at a directory; readFile on a binary file that readTextFile refuses to decode; a race where the file is deleted between resolveReadableSandboxPath and readTextFile; a sandbox that returns null for unreadable/permission-denied files.

Common situations: Model-driven tool calls reading directories as if they were files; reading binary artifacts (images, compiled output) that only support text reads; TOCTOU races in active sandboxes; permissions restricted inside the sandbox container.

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


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/8c5b9319e8af5d16. Report an issue: GitHub.

Appendix: source

Thrown at packages/harness-cline/src/cline-remote-ops.ts:203

    }

    const resolvedPath = lastOutputLine(result.output);
    if (!resolvedPath) {
      throw new Error(`Unable to resolve path: ${inputPath}`);
    }
    return assertWorkspacePath(resolvedPath);
  };

  const readFile = async (inputPath: string): Promise<string> => {
    const remotePath = resolvePath(inputPath);
    const resolved = await resolveReadableSandboxPath({
      remotePath,
      inputPath,
      missingMessage: `File not found: ${inputPath}`,
    });
    const content = await sandbox.readTextFile({ path: resolved });
    if (content == null) {
      throw new Error(`File not found: ${inputPath}`);
    }
    return content;
  };

  const writeFile = async (
    inputPath: string,
    content: string,
  ): Promise<void> => {
    const remotePath = resolvePath(inputPath);
    const resolved = await resolveWritableSandboxPath({
      remotePath,
      inputPath,
    });
    // `writeTextFile` creates parent directories recursively per the
    // SandboxSession contract, so no explicit mkdir is needed.
    await sandbox.writeTextFile({ path: resolved, content });
  };

View on GitHub (pinned to 69428b1f8b)