ErrLookup › Background articles › FileNotFoundException: "could not find file" — missing assets, wrong paths, dead downloads, and stripped embedded resources
FileNotFoundException: "could not find file" — missing assets, wrong paths, dead downloads, and stripped embedded resources
FileNotFoundException is thrown when code tries to open, read, or promote a file that does not exist at the resolved path. Developers meet it when a bundled asset is missing after install, a relative path resolves against the wrong working directory, a case-sensitive filesystem rejects a path that worked on Windows, an embedded resource was dropped by trimming, or a library maps an upstream HTTP 404 onto this exception. This article covers the family across 53 repositories: the layers that produce it, the causes that recur regardless of library, and the checks that prevent it.
Distilled from 204 documented records across 53 repositories.
Background
FileNotFoundException originates at the boundary between a path string and the filesystem. In the .NET Base Class Library it is thrown natively by File.Open and read APIs, and most libraries in this family add an explicit File.Exists guard before their own work so the error carries the offending path in a predictable place: DevToys' FileStorage.OpenReadFile, Playnite's DatabaseAPI.AddFile, PDFPatcher's OpenPdfFile, and OfficeCLI's OLE embedding all follow this guard-then-throw shape. From the caller's side it always looks the same — an exception whose message or FileName property names a path the code believed existed — but the reason the path is dead varies: the file was never written (UniGetUI promoting a .part download that never completed), it was deleted between a check and a use (Subtitle Edit batch jobs, stale FileInfo objects in DevToys), or it resolved against the wrong root (relative paths resolved against the CWD, a wrong FLINK_HOME for Flink's GPU discovery script).
A second cluster has nothing to do with the disk. Orleans Dashboard and jadx throw FileNotFoundException when an embedded manifest resource or classpath resource cannot be opened — a packaging defect, not a filesystem one — and .NET trimming or single-file publishes make this worse by silently dropping embedded assets. Wand-Enhancer shows the degenerate case: a resource name returned by GetManifestResourceNames() itself fails to open, signaling a corrupt assembly load. Subtitle Edit's DownloadHelper maps an upstream HTTP 404 onto FileNotFoundException deliberately, so a dead release-asset URL surfaces as a file-not-found and is excluded from the retry loop as a permanent condition rather than a transient network error. Kestra re-throws it when a namespace-file revision does not exist. A few records use the exception type as a general lookup-failed signal: Playnite fires it when an emulator profile's StartupExecutable regex matches no file, and one Flink Parquet record associates it with a physical-type/logical-type mismatch — behavior in those cases is library-specific and should be read on the record page.
Because the exception type itself says only "the thing is not there," diagnosis reduces to three questions: where did the path come from (user input, config, convention, a previous operation's output such as GetPartialPath or GetBackupPath), what root was it resolved against (working directory, AppCacheDirectory, FLINK_HOME, a JS script root, an emulator InstallDir, a mod's mounted file system in OpenRA), and did the file ever exist at that location (packaging, antivirus quarantine, version-control omission, a concurrent cleanup path). The 30 best-documented records show the answers cluster into a short list of recurring causes, ordered below by how often they appear.
Platform and build configuration matter as much as the library. Records from MonoGame, Playnite, OpenRA, and better-genshin-impact repeatedly flag case-sensitivity mismatches that only fire on Linux/macOS, because 'Track.MP3' and 'track.mp3' are different files there. MonoGame and better-genshin-impact records also treat build configuration — CopyToOutputDirectory and Content build actions in .csproj files — as a first-class cause, since a file present in the repository but never copied to build output is indistinguishable from a file that was never shipped.
Common causes
- Missing bundled asset or incomplete installation.The file should have shipped with the application but is absent: better-genshin-impact's config.json, LeyLineOutcropData.json, template icons, and PaddleOCR inference.yml; Unity's Unity.Sdk nupkg and .version files; Subtitle Edit's nOCR database; jadx's export templates. Causes include corrupted installs, antivirus quarantine, .gitignore rules excluding sidecar files, and incomplete re-downloads after version bumps.
- Wrong path or resolution against the wrong root.Relative paths resolve against an unexpected working directory (PDFPatcher batch jobs, OfficeCLI OLE sources, Subtitle Edit CLI), or against the wrong base entirely — Flink resolves discovery-script paths against FLINK_HOME, DevToys against AppCacheDirectory, better-genshin-impact's JS loader against the script root. Typos, wrong relative depth, and missing .js extensions in import specifiers fall in the same bucket.
- Build output not copied.The file exists in the repository but not in build output because CopyToOutputDirectory or the Content build action is not set (better-genshin-impact assets, MonoGame audio and font assets), or because CI checked out the repo without the asset committed to version control.
- Case-sensitivity mismatch on Linux/macOS.A path that works on case-insensitive Windows fails on case-sensitive filesystems. MonoGame's MP3/OGG importers, Playnite's database AddFile, OpenRA's sprite YAML paths, and DevToys' cross-platform file storage all document exact-casing requirements.
- Embedded resource missing or stripped.Orleans Dashboard assets marked incorrectly or removed by trimming/single-file publish; jadx template resources absent from an incomplete distribution; renamed or mis-cased resource names that do not match GetManifestResourceStream lookups. The file system is fine — the packaged assembly is not.
- TOCTOU race or stale metadata.The file existed at the check but not at the open: a concurrent cleanup thread or antivirus removes a .part file between download and promotion (UniGetUI); a PDF disappears from the job list mid-batch (PDFPatcher); FileInfo's cached Exists value goes stale because Refresh() was never called (DevToys SimpleSandboxedFileReader).
- Path mismatch between paired operations.Two operations must use the identical path string but do not: UniGetUI's download and promote with different destinationPath values, Playnite's EAC settings at a hardcoded non-standard location, kestra referencing a file revision from the wrong namespace, backups renamed or moved out of the managed folder (nopCommerce).
- Upstream artifact gone (HTTP 404).Subtitle Edit's DownloadHelper converts a 404 response into FileNotFoundException — the wrong release tag, a renamed or removed GitHub release asset, or a restructured CDN path. It propagates immediately and is excluded from the retry loop as a permanent condition.
What usually fixes it
- Guard before you open: pair every read, import, or promote with an immediate File.Exists (or FileInfo.Refresh() then Exists) check at the boundary, and handle the false branch with a clear message or graceful skip instead of letting the raw exception escape — the pattern used by DevToys, Playnite, PDFPatcher, and OfficeCLI in these records.
- Normalize paths early: resolve user- and config-supplied paths to absolute form with Path.GetFullPath against a known base, use the identical path string for paired operations (download then promote, write then read), and log the resolved path so missing-file reports name where the code actually looked.
- Verify packaging and build configuration: mark content assets with CopyToOutputDirectory/Content build actions, ship model sidecar configs (e.g. inference.yml) with their binaries, exclude dashboard-like assemblies from trimming in single-file publishes, and smoke-test in CI that every embedded resource opens and every referenced asset path exists in the checkout.
- Respect case sensitivity and platform roots: match exact on-disk casing on Linux/macOS, install required font packages on CI build machines, and verify environment-derived roots (FLINK_HOME, AppCacheDirectory) before relying on relative paths.
- Shrink and defend the TOCTOU window: construct readers in the same step that confirmed existence, re-check existence after long-running prior steps, and audit for concurrent cleanup paths or antivirus interference that removes files between operations.
- Treat permanent conditions as permanent: when a missing file stems from a 404 or a nonexistent revision, do not burn retries — confirm upstream, update the pinned release tag or path, or omit the revision to fetch the current version.
Go deeper
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Documented occurrences
- The completed updater partial file was not found.(Devolutions/UniGetUI)
- Emulator executable not found. Regular expression lookup: {profileDef.StartupExecutable}(JosefNemec/Playnite)
- Embedded resource not found: {fullResourceName}(dotnet/orleans)
- PaddleOCR config file {modelConfigFileName} not found: {configFilePath}(babalae/better-genshin-impact)
- LeyLineOutcropData.json 未找到(babalae/better-genshin-impact)
- Multiple-replace file not found: {path}(SubtitleEdit/subtitleedit)
- 模板素材未找到(babalae/better-genshin-impact)
- Unable to find the indicated file.(DevToys-app/DevToys)
- No {prefix}*{suffix} package found in {sdkNugetsPath}(Unity-Technologies/UnityCsReference)
- The gpu discovery script does not exist in path %s.(apache/flink)
- OLE source file not found: {srcPath}(iOfficeAI/OfficeCLI)
- Could not find "{input.FontName}" font file at "{fontFile}".(MonoGame/MonoGame)
- The requested URL was not found: {url}(SubtitleEdit/subtitleedit)
- config.json 未找到(babalae/better-genshin-impact)
- Cannot add file to database, file not found.(JosefNemec/Playnite)
- EAC launcher settings not found: {settingsPath}(JosefNemec/Playnite)
- 找不到文件:{sourceFile}(wmjordan/PDFPatcher)
- Unable to find the indicated file.(DevToys-app/DevToys)
- JAR file is not a file: {}(apache/flink)
- Could not find "{input.FontName}" font file at "{fontFile}".(MonoGame/MonoGame)
…and 184 more across the corpus — use search.
Honest provenance: generated on 2026-08-14 from AI-assisted analysis of the linked records. See how records are made.