Debugging System.IO.FileNotFoundException - Cause and fix

This is the third part in the series named "Debugging common .NET exceptions". Today, I want to help you track down and fix a very common and very well known exception, System.IO.FileNotFoundException. Admitted! In all instances this error is caused by trying to access a file that isn't there. But, there are actually multiple scenarios that can trigger this exception. You may think you know everything there is to know about this exception, but I bet there is something left for you to learn. At least I did while digging down into the details for this post. Stay tuned to get the full story.

Types of file not found errors

Let's dig into the different causes of this error. The Message property on FileNotFoundException gives a hint about what is going on.

Could not find file 'filename'

As the message says, you are trying to load a file that couldn't be found. This type of error can be re-created using a single line of code:

line 3 is the important one here. I'm trying to load a file that doesn't exist on the file system (non-existing.file). In the example above, the program will print an output to the console looking similar to this:

APP_PATH will be the absolute path to the file that cannot be found. This type of FileNotFoundException actually contains all the information needed to debug the problem. The exception message contains a nice error description, as well as an absolute path to the missing file. If you want to present the user with the path or maybe create the file when not found, there is a nifty property available on FileNotFoundException:

catch (FileNotFoundException e)
{
File.Create(e.FileName);
}

In the example I simply create the missing file by using the Filename property. I've seen code parsing the exception message to get the name of the missing file, which is kind of a downer when the absolute path is available right there on the exception :)

The system cannot find the file specified. (Exception from HRESULT: 0x80070002)

This error is typically thrown when trying to load an assembly that doesn't exist. The error can be re-created like this:

In this scenario, the program still throws a FileNotFoundException. But the exception message is different:

System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
at System.Reflection.RuntimeAssembly.nLoadFile(String path, Evidence evidence)
at System.Reflection.Assembly.LoadFile(String path)
at ConsoleApp.Program.Main(String[] args) in APP_PATH\Program.cs:line 20

Unlike the error thrown on reading the missing file, messages from the System.Reflection namespace are harder to understand. To find the cause of this error you will need to look through the stack trace, which hints that this is during Assembly.LoadFile. Notice that no filename is present in the exception message and in this case, the Filename property on FileNotFoundException is null.

Could not load file or assembly 'assembly' or one of its dependencies. The system cannot find the file specified.

An error similar to the one above is the Could not load file or assembly 'assembly' or one of its dependencies. The system cannot find the file specified. error. This also means that the program is trying to load an assembly that could not be found. The error can be re-created by creating a program that uses another assembly. Build the program, remove the references assembly (the .dll file) from the bin\Debug folder and run the program. In this case, the program fails during startup:

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Lib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
at ConsoleApp.Program.Main(String[] args)

In this example, I'm referencing an assembly named Lib, which doesn't exist on the disk or in the Global Assembly Cache (GAC).

The typical cause of this error is that the referenced assembly isn't on the file system. There can be multiple causes of this. To help you debug this, here are some things to check:

If you are deploying using a system like Azure DevOps or Octopus Deploy, make sure all the files from the build output are copied to the destination.

Right click the referenced assembly in Visual Studio, click Properties and make sure that Copy Local is set to true:

Access errors when running on IIS

Until now all instances of this error have been a missing file from disk. I want to round off this post with a quick comment about security. In some cases, the FileNotFoundException can be caused by the user account trying to access the file, and simply don't have the necessary access. Under optimal circumstances, the framework should throw a System.UnauthorizedAccessException when this happens. But I have seen the issue in the past when hosting websites on IIS. Make sure that the ASP.NET worker process account (or NETWORK SERVICE depending on which user you are using) has access to all files and folders needed to run the application.