vercel/ai · error

File not found: ${inputPath}

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.

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)

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.