{"record":{"id":"b60fee6fc3ca372a","repo":"DevToys-app/DevToys","slug":"unable-to-find-the-indicated-file-b60fee","errorCode":null,"errorMessage":"Unable to find the indicated file.","messagePattern":"Unable to find the indicated file\\.","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"error","filePath":"src/app/dev/DevToys.Api/Core/SimpleSandboxedFileReader.cs","lineNumber":21,"sourceCode":"/// <summary>\n/// Represents a read-only access to a file on the file system.\n/// </summary>\n/// <remarks>\n/// The file can be read and accessed multiple times in parallel.\n/// In some cases, the file's resulting stream is non-seekable.\n/// Disposing the <see cref=\"SandboxedFileReader\"/> will close the access to the file.\n/// </remarks>\n[DebuggerDisplay($\"FileName = {{{nameof(FileName)}}}\")]\ninternal sealed class SimpleSandboxedFileReader : SandboxedFileReader\n{\n    private readonly FileInfo _fileInfo;\n\n    internal SimpleSandboxedFileReader(FileInfo fileInfo)\n        : base(fileInfo.Name)\n    {\n        if (!fileInfo.Exists)\n        {\n            throw new FileNotFoundException(\"Unable to find the indicated file.\", fileInfo.FullName);\n        }\n\n        _fileInfo = fileInfo;\n    }\n\n    protected override ValueTask<Stream> OpenReadFileAsync(CancellationToken cancellationToken)\n    {\n        if (!_fileInfo.Exists)\n        {\n            throw new FileNotFoundException(\"Unable to find the indicated file.\", _fileInfo.FullName);\n        }\n\n        return ValueTask.FromResult(\n            (Stream)new FileStream(\n                _fileInfo.FullName,\n                FileMode.Open,\n                FileAccess.Read,\n                FileShare.Read,","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/DevToys-app/DevToys/blob/7e12df8448aa1f6aec4a8736b3e06a1c90530715/src/app/dev/DevToys.Api/Core/SimpleSandboxedFileReader.cs#L3-L39","documentation":"Thrown by the SimpleSandboxedFileReader constructor (SandboxedFileReader.FromFileInfo path) when the supplied FileInfo reports Exists == false at construction time. SimpleSandboxedFileReader wraps a read-only, share-read file access (FileMode.Open, FileShare.Read, async/sequential). Because FileInfo caches its Exists value, a stale FileInfo from before the file was deleted will still trip this guard.","triggerScenarios":"Constructing SimpleSandboxedFileReader (via SandboxedFileReader.FromFileInfo) with a FileInfo whose underlying file was deleted, moved, or never written; passing a FileInfo captured long before use without calling Refresh(); a picked file the user removed from disk between selection and open.","commonSituations":"User picks a file in the file dialog then deletes/renames it externally before the read; a temp file cleaned up by the OS or another process; cross-device path resolution where the FileInfo FullName points somewhere unreachable.","solutions":["Call fileInfo.Refresh() right before constructing the reader so Exists reflects current disk state.","Guard with `if (!fileInfo.Exists) return;` (or reprompt) before FromFileInfo.","For user-picked files, re-validate existence immediately before opening and surface a friendly message if missing.","Wrap FromFileInfo in try/catch (FileNotFoundException) and recover by reprompting or skipping."],"exampleFix":"// before\nvar reader = SandboxedFileReader.FromFileInfo(fileInfo);\n\n// after\nfileInfo.Refresh();\nif (!fileInfo.Exists)\n{\n    // reprompt / log / abort\n    return;\n}\nvar reader = SandboxedFileReader.FromFileInfo(fileInfo);","handlingStrategy":"validation","validationCode":"// Refresh defeats FileInfo's cached Exists before constructing the reader.\nfileInfo.Refresh();\nif (!fileInfo.Exists)\n{\n    // file gone — reprompt / abort\n    return;\n}\nSandboxedFileReader reader = SandboxedFileReader.FromFileInfo(fileInfo);","typeGuard":null,"tryCatchPattern":"try\n{\n    SandboxedFileReader reader = SandboxedFileReader.FromFileInfo(fileInfo);\n}\ncatch (FileNotFoundException ex)\n{\n    // source file vanished before construction — reprompt the user or skip\n}","preventionTips":["Call FileInfo.Refresh() immediately before FromFileInfo; the cached Exists value is a common trap.","Keep the gap between pick and open as short as possible to shrink the TOCTOU window.","Re-validate user-picked files right before reading and surface a friendly message if missing.","Construct the reader in the same synchronous step that confirmed existence."],"tags":["csharp","file-io","sandboxed-file-reader","toctou","stale-cache"],"backgroundTag":null,"analyzedSha":"7e12df8448aa1f6aec4a8736b3e06a1c90530715","analyzedAt":"2026-08-13T10:27:33.924Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}