iOfficeAI/OfficeCLI · error · FileNotFoundException

File not found

Error message

File not found: {path}

What it means

Thrown by FileSource.ResolveFile when the given filesystem path does not exist (File.Exists returns false). It surfaces as a FileNotFoundException with the offending path so the caller can distinguish a missing-file cause from other resolution failures.

Solutions

  1. Verify the file exists at the given path (check working directory for relative paths).
  2. Use an absolute path to remove working-directory ambiguity.
  3. On case-sensitive filesystems, confirm the exact casing of the filename.

Example fix

// before
var (stream, ext) = FileSource.Resolve("assets/logo.png"); // cwd-relative
// after
var path = Path.Combine(AppContext.BaseDirectory, "assets", "logo.png");
var (stream, ext) = FileSource.Resolve(path);
Defensive patterns

Strategy: validation

Validate before calling

static (MemoryStream, string) ResolveExistingFile(string path)
{
    var full = Path.GetFullPath(path);
    if (!File.Exists(full))
        throw new FileNotFoundException($"File not found: {full}");
    return FileSource.Resolve(full);
}

Try / catch

try { var r = FileSource.Resolve(path); }
catch (FileNotFoundException ex) when (ex.Message.StartsWith("File not found"))
{ /* report missing asset, offer a picker */ }

Prevention

When it happens

Trigger: Calling FileSource.Resolve with a plain path (no data:/http(s):// prefix) that does not point to an existing file; relative path resolved against an unexpected working directory.

Common situations: Wrong working directory making a relative path unresolvable; path from config pointing to a moved/deleted asset; missing asset in a deployment; case-sensitivity mismatch on Linux.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/e67222b44d499ab5. Report an issue: GitHub.

Appendix: source

Thrown at src/officecli/Core/FileSource.cs:86

    /// Resolve a source to text lines (for CSV/text data).
    /// </summary>
    public static string[] ResolveLines(string source)
    {
        var (stream, _) = Resolve(source);
        using (stream)
        {
            using var reader = new StreamReader(stream);
            var text = reader.ReadToEnd();
            return text.Split('\n')
                .Select(l => l.TrimEnd('\r'))
                .ToArray();
        }
    }

    private static (MemoryStream, string) ResolveFile(string path)
    {
        if (!File.Exists(path))
            throw new FileNotFoundException($"File not found: {path}");
        return (new MemoryStream(File.ReadAllBytes(path)), Path.GetExtension(path).ToLowerInvariant());
    }

    private static (MemoryStream, string) ResolveUrl(string url)
    {
        // SSRF guard: same connect-time public-IP enforcement as image fetch —
        // refuse loopback / private / link-local / cloud-metadata targets. See
        // SsrfGuard. Without this, a caller-supplied data=/model3d=/media= URL
        // is an SSRF primitive when officecli runs on untrusted input.
        var handler = SsrfGuard.CreateGuardedHandler("file");

        using var client = new HttpClient(handler, disposeHandler: true) { Timeout = TimeSpan.FromSeconds(30) };
        client.DefaultRequestHeaders.Add("User-Agent", "OfficeCLI");

        var response = client.GetAsync(url).GetAwaiter().GetResult();
        response.EnsureSuccessStatusCode();

        // Bound memory use: fail fast on an honest oversized Content-Length, then

View on GitHub (pinned to 1ced45e900)