System.IO.FileNotFoundException

A FileNotFoundException is thrown when your code tries to open a file that does not exist at the path it was given. The message contains the full path that was searched, and the FileName property holds it too: Could not find file 'C:\app\settings.json'.

The same exception is thrown when .NET cannot load an assembly, with the message Could not load file or assembly. The cause is the same, a file that is not where it was expected.

Minimum version: >= 1.1 >= Core 2.0

Statistics

5
elmah.io logo 16

Common causes

The file is missing, or it is not where the code looks. The full path in the message shows where the code looked, which is the best clue.

A relative path that is resolved from the wrong folder

A relative path is resolved against the current working directory, not the folder of the application. The working directory depends on how the application is started, so a path that works in Visual Studio can fail when the app runs as a service.

var json = File.ReadAllText("settings.json");   // looks in the current working directory

Build the path from the folder of the application:

var path = Path.Combine(AppContext.BaseDirectory, "settings.json");
var json = File.ReadAllText(path);

A file that is part of your project is not copied to the build output unless you ask for it. It works on your machine because you opened the file from the source folder, and fails on the server.

Set the file to be copied in the project file, and check the published output:

<ItemGroup>
  <None Update="settings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

Windows ignores the case of file names, and accepts both / and \. On Linux, file names are case sensitive, and the separator is /. A path such as Data\Orders.CSV that works on a Windows machine can fail in a Linux container when the file is called orders.csv.

Build paths with Path.Combine, and use the exact casing of the file name:

var path = Path.Combine("Data", "orders.csv");
var content = File.ReadAllText(path);

When the message says Could not load file or assembly, an assembly or one of its dependencies is not in the application folder. This often happens when only some of the files of a build are copied to the server.

Publish the application with dotnet publish and deploy all of the output. The FileName property holds the name and version of the assembly, so you can see which one is missing.

How to fix it and prevent it

Build paths from a known folder

Use AppContext.BaseDirectory, the content root in ASP.NET Core, or Environment.GetFolderPath as the starting point. Never depend on the working directory.

var template = Path.Combine(AppContext.BaseDirectory, "templates", "invoice.html");
var data = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

If a file is optional, check for it before you open it. The file can still disappear between the check and the open, so keep the exception handler for the cases where that matters.

var path = Path.Combine(AppContext.BaseDirectory, "overrides.json");

if (File.Exists(path))
{
    var json = File.ReadAllText(path);
}

Check that the files your code opens are in the folder you deploy, not only in the project. A quick listing of the publish folder before a release finds files that were left out.

How to find the missing file

The message and the FileName property tell you the full path that was used, and the stack trace shows who asked for it:

System.IO.FileNotFoundException: Could not find file 'C:\src\Shop\bin\Debug\net10.0\settings.json'.
File name: 'C:\src\Shop\bin\Debug\net10.0\settings.json'
   at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Int32 bufferSize)
   at System.IO.File.ReadAllText(String path, Encoding encoding)
   at Shop.Services.SettingsLoader.Load() in C:\src\Shop\Services\SettingsLoader.cs:line 9
   at Program.<Main>$(String[] args) in C:\src\Shop\Program.cs:line 4

The path in the message is C:\src\Shop\bin\Debug\net10.0\settings.json, which is the working directory plus the relative path from line 9 of SettingsLoader.cs. Compare it to where the file really is. If the folder is the problem, build the path from AppContext.BaseDirectory. If the file is missing, check that it was copied or deployed.

Should you catch it?

Yes, this is one of the exceptions where catching makes sense. A file can be missing for reasons you cannot check ahead, such as a user deleting it, and a check with File.Exists still leaves a small gap between the check and the open.

Catch it close to the call, decide what the fallback is, and log the path so you can see what was missing.

var path = Path.Combine(AppContext.BaseDirectory, "settings.json");

try
{
    var json = File.ReadAllText(path);
}
catch (FileNotFoundException e)
{
    logger.LogWarning(e, "Settings file {Path} was not found, using defaults", e.FileName);
}

Find FileNotFoundException before your users do

elmah.io logs every unhandled exception in your .NET application with its stack trace and request details, groups identical errors and notifies you when a new one appears.

Start free trial
Free 21-day trial No credit card required

Related exceptions

Frequently asked questions

Why does it say the file is missing when I can see it?

The path your code uses is not the one you are looking at. Read the full path in the message, and check the working directory, the casing and any extra extension such as settings.json.txt. Also check that the process is running as the user and on the machine you think it is.

A FileNotFoundException means the folder exists but the file does not. A DirectoryNotFoundException means a folder in the path does not exist.

It is fine for optional files. It does not remove the need for an exception handler, because the file can be deleted or locked between the check and the open.

It is a FileNotFoundException or a FileLoadException from the runtime. An assembly, or a dependency of it, was not found or has the wrong version. Compare the deployed files with the output of dotnet publish.

Let your AI agent track it down

Connect Claude Code, Cursor, VS Code or Visual Studio to the elmah.io MCP server and ask your agent to look into FileNotFoundException for you. For example:

AI chat
Find the most frequent FileNotFoundException in my production log and show me the line that throws it.

The agent reads the stack trace and request details from elmah.io, finds the code in your repository and proposes a fix. In Claude Code, add the server with one command:

claude mcp add --transport http --client-id claudecode elmahio https://mcp.elmah.io/mcp

The MCP server is included on every plan and is currently in beta. Set up the MCP server.

Further reading

YouTube videos

Answers from Stack Overflow

Believe it or not, this is normal behaviour. An exception is thrown but handled by the XmlSerializer, so if you just ignore it everything should continue on fine.

I have found this very annoying, and there have been many complaints about this if you search around a bit, but from what I've read Microsoft don't plan on doing anything about it.

You can avoid getting Exception popups all the time while debugging if you switch off first chance exceptions for that specific exception. In Visual Studio, go to Debug -> Exceptions (or press Ctrl + Alt + E), Common Language Runtime Exceptions -> System.IO -> System.IO.FileNotFoundException.

You can find information about another way around it in the blog post C# XmlSerializer FileNotFound exception (which discusses Chris Sells' tool XmlSerializerPreCompiler).

By Martin Sherburn. Read the original answer on Stack Overflow.

In My case, the file appsettings.json existed in the project folder, but it was set to Do not copy, I changed the setting to Copy always (see images below). And it worked for me.

It will automatically add the following XML to your project.csproj file:

<ItemGroup>
    <Content Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
</ItemGroup>

I have looked at other answers, project.json is dead as this answer says.

enter image description here

enter image description here

By Maytham Fahmi. Read the original answer on Stack Overflow.

For your specific problem, it looks like you have a mismatch in your resolved dependencies. When things like this happen it's likely because you're running your application on an incompatible dnx. We're still making very big breaking changes so if you ever see method missing of type missing, chances are you ended up running betaX packages and betaY dnx or vice versa.

Even more specifically, Assembly Neutral Interfaces were removed in beta4 but it looks like the application you are running is still using them.

We have plans to make it so that packages can mark the minimum dnx that they require to run to make the error message more clear. Also as time goes by, the breaking changes will die down.

In general though, I feel like it's time I wrote a guide on how to diagnose issues like this when using the dnx (since it's pretty different to existing .NET).

Dependencies you put into project.json are top level only. Versions are also always minimums (it's just like a NuGet package). This means that when you specify Foo 1.0.0-beta4 you're really specifying Foo >= 1.0.0-beta4. This means if you ask for MVC 0.0.1 and the minimum versions on your configured feed is MVC 3.0.0, you'll get that one. We also NEVER float your version unless you specify it. If you ask for 1.0.0 and it exists, you will get 1.0.0 even if newer versions exist. Specifying empty versions is ALWAYS bad and will be disallowed in later builds.

There's a new feature we're introducing to NuGet called floating versions. Today it only works on the prerelease tag, but in the next version it'll work on more parts of the version. This is similar to npm and gem syntax for specifying version ranges in the package specification file.

1.0.0-* - Means give me the HIGHEST version matching the prefix (according to semantic versioning rules) OR if there is no version matching that prefix, use normal behavior and get me the LOWEST version >= the specified version.

When you run restore in the latest builds, it will write out a file called project.lock.json. This file will have the transitive closure of dependencies for all target frameworks defined in project.json.

When something like this fails you can do the following:

Take a look at the resolved dependencies using kpm list. This will show you the resolved versions of packages referenced by your project and what dependency pulled it in. e.g. if A -> B, it'll show:

A
  -> B
B
 ->

Actual KPM list output:

Listing dependencies for ClassLibrary39 (C:\Users\davifowl\Documents\Visual Studio 14\Projects\ClassLibrary39\src\ClassLibrary39\project.json)

[Target framework DNX,Version=v4.5.1 (dnx451)]

 framework/Microsoft.CSharp 4.0.0.0
    -> ClassLibrary39 1.0.0
 framework/mscorlib 4.0.0.0
    -> ClassLibrary39 1.0.0
 framework/System 4.0.0.0
    -> ClassLibrary39 1.0.0
 framework/System.Core 4.0.0.0
    -> ClassLibrary39 1.0.0
*Newtonsoft.Json 6.0.1
    -> ClassLibrary39 1.0.0

[Target framework DNXCore,Version=v5.0 (dnxcore50)]

*Newtonsoft.Json 6.0.1
    -> ClassLibrary39 1.0.0
 System.Runtime 4.0.20-beta-22709
    -> ClassLibrary39 1.0.0

* means direct dependency.

If you have a working visual studio (which breaks with DNX right now), you can look at the references node. It has the same data represented visually:

References node

Let's look at what a dependency failure looks like:

Here's the project.json

{
    "version": "1.0.0-*",
    "dependencies": {
        "Newtonsoft.Json": "8.0.0"
    },

    "frameworks" : {
        "dnx451" : { 
            "dependencies": {
            }
        },
        "dnxcore50" : { 
            "dependencies": {
                "System.Runtime": "4.0.20-beta-22709"
            }
        }
    }
}

Newtonsoft.Json 8.0.0 doesn't exist. So running kpm restore shows the following:

enter image description here

When diagnosing when restore might have failed, look at the HTTP requests made, they tell you what configured package sources kpm looked in. Notice in the above image, there is a CACHE request. This is the built in caching based on the type of resource (nupkg or nuspec) and has a configurable TTL (look at kpm restore --help). If you want to force kpm to hit the remote NuGet sources, use the --no-cache flag:

KPM restore --no-cache

These errors also show up in Visual Studio in the package manager log output window:

enter image description here

Side note!

Package Sources

I'll describe the way NuGet.config works right now (which will likely change in the future). By default you have a NuGet.config with the default NuGet.org source configured globally in %appdata%\NuGet\NuGet.Config. You can manage these global sources within visual studio or with the NuGet command line tool. You should always look at your effective sources (the ones listed in the kpm output) when trying to diagnose failures.

Read more about NuGet.config here

Back to reality:

When dependencies are unresolved, running the application will give you this:

> dnx . run
System.InvalidOperationException: Failed to resolve the following dependencies for target framework 'DNX,Version=v4.5.1':
   Newtonsoft.Json 8.0.0

Searched Locations:
  C:\Users\davifowl\Documents\Visual Studio 14\Projects\ClassLibrary39\src\{name}\project.json
  C:\Users\davifowl\Documents\Visual Studio 14\Projects\ClassLibrary39\test\{name}\project.json
  C:\Users\davifowl\.dnx\packages\{name}\{version}\{name}.nuspec
  C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\{name}.dll
  C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\Facades\{name}.dll
  C:\WINDOWS\Microsoft.NET\assembly\GAC_32\{name}\{version}\{name}.dll
  C:\WINDOWS\Microsoft.NET\assembly\GAC_64\{name}\{version}\{name}.dll
  C:\WINDOWS\Microsoft.NET\assembly\GAC_MSIL\{name}\{version}\{name}.dll

Try running 'kpm restore'.

   at Microsoft.Framework.Runtime.DefaultHost.GetEntryPoint(String applicationName)
   at Microsoft.Framework.ApplicationHost.Program.ExecuteMain(DefaultHost host, String applicationName, String[] args)
   at Microsoft.Framework.ApplicationHost.Program.Main(String[] args)

The runtime basically tries to validate that the entire dependency graph is resolved before attempting to run. If it suggests running kpm restore it's because it can't find the dependencies listed.

Another reason why you might get this error is if you're running the wrong dnx flavor. If your application only specifies dnx451 and you try to run the CoreCLR dnx, you might see a similar problem. Pay close attention to the target framework in the error message:

For running:

dnx4x - runs on dnx-clr-{etc}
dnxcore50 - runs on dnx-coreclr-{etc}

When you're trying to run, you should remember that mental mapping from clr to target framework defined in your project.json.

This also shows up in Visual Studio under the references node: Unresolved dependencies

The nodes marked as yellow are unresolved.

These also show up in the error list:

Error list unresolved dependencies

Building

These errors also show up when building. When building from the command line, the output is very verbose and can be extremely useful when diagnosing problems:

> kpm build

Building ClassLibrary39 for DNX,Version=v4.5.1
  Using Project dependency ClassLibrary39 1.0.0
    Source: C:\Users\davifowl\Documents\Visual Studio 14\Projects\ClassLibrary39\src\ClassLibrary39\project.json

  Using Assembly dependency framework/mscorlib 4.0.0.0
    Source: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\mscorlib.dll

  Using Assembly dependency framework/System 4.0.0.0
    Source: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.dll

  Using Assembly dependency framework/System.Core 4.0.0.0
    Source: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.Core.dll

  Using Assembly dependency framework/Microsoft.CSharp 4.0.0.0
    Source: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\Microsoft.CSharp.dll


Building ClassLibrary39 for DNXCore,Version=v5.0
  Using Project dependency ClassLibrary39 1.0.0
    Source: C:\Users\davifowl\Documents\Visual Studio 14\Projects\ClassLibrary39\src\ClassLibrary39\project.json

  Using Package dependency System.Console 4.0.0-beta-22709
    Source: C:\Users\davifowl\.dnx\packages\System.Console\4.0.0-beta-22709
    File: lib\contract\System.Console.dll

  Using Package dependency System.IO 4.0.10-beta-22231
    Source: C:\Users\davifowl\.dnx\packages\System.IO\4.0.10-beta-22231
    File: lib\contract\System.IO.dll

  Using Package dependency System.Runtime 4.0.20-beta-22231
    Source: C:\Users\davifowl\.dnx\packages\System.Runtime\4.0.20-beta-22231
    File: lib\contract\System.Runtime.dll

  Using Package dependency System.Text.Encoding 4.0.10-beta-22231
    Source: C:\Users\davifowl\.dnx\packages\System.Text.Encoding\4.0.10-beta-22231
    File: lib\contract\System.Text.Encoding.dll

  Using Package dependency System.Threading.Tasks 4.0.10-beta-22231
    Source: C:\Users\davifowl\.dnx\packages\System.Threading.Tasks\4.0.10-beta-22231
    File: lib\contract\System.Threading.Tasks.dll

The output shows all of the assemblies passed into the compiler from packages and project references. When you start getting build failures, it's useful to look here to make sure that the package you are using actually works on that target platform.

Here's an example of a package that doesn't work on dnxcore50:

{
    "version": "1.0.0-*",
    "dependencies": {
        "Microsoft.Owin.Host.SystemWeb": "3.0.0"
    },

    "frameworks": {
        "dnx451": {
            "dependencies": {
            }
        },
        "dnxcore50": {
            "dependencies": {
                "System.Console": "4.0.0-beta-22709"
            }
        }
    }
}

Microsoft.Owin.Host.SystemWeb version 3.0.0 does not have any assemblies that run on dnxcore50 (take a look at the unzipped package's lib folder). When we run kpm build:

Missing assemblies on dnxcore50

Notice it says "using Package Microsoft.Owin.Host.SystemWeb" but there is not "File:". This could be the reason for a build failure.

By davidfowl. Read the original answer on Stack Overflow.

Update:

From @bunjeeb in comments. Use System.AppContext.BaseDirectory instead of Assembly.GetEntryAssembly().Location for .NET 5 <= with <PublishSingleFile>true</PublishSingleFile>.

Original:

For me the error was using Directory.GetCurrentDirectory(). This worked fine running locally but on a production server it failed when the program was started from Powershell. Replaced with Assembly.GetEntryAssembly().Location and everything worked.

Complete code:

var builder = new ConfigurationBuilder()
        .SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))
        .AddJsonFile("appsettings.json");

var configuration = builder.Build();

By Ogglas. Read the original answer on Stack Overflow.

I solved this problem by adding Newtonsoft.Json to the NuGet of the startup project (even though it is not directly used in the startup project).

By Feng Jiang. Read the original answer on Stack Overflow.