.NET Exceptions – System.IO.PathTooLongException

Today, on our continued journey through the in-depth .NET Exception Handling series, we’ll be taking a closer look at the System.IO.PathTooLongException in .NET. As the name implies, the System.IO.PathTooLongException is usually thrown when a path is passed to a variety of System.IO namespaced methods that is too long for the current .NET version and/or operating system configuration.

In this article we’ll examine the System.IO.PathTooLongException in more detail, starting with how the exception fits into the larger .NET Exception hierarchy. We’ll then take a brief look at what path sizes are allowed, along with some functional C# code samples that illustrate how System.IO.PathTooLongExceptions are commonly thrown and can be avoided, so let’s get to it!

The Technical Rundown

Full Code Sample

Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.

When Should You Use It?

One of the biggest challenges when dealing with IO during development can be handling local file creation and access. From permissions to synchronicity to path structure and length, every platform has slightly different rules you must abide by. Therefore, exceptions like the System.IO.PathTooLongException that we’re looking at today must be present to handle outside cases.

Since we’ll be looking at the maximum allowed path length, let’s briefly go over the piece that make up a full path. We can use the System.IO.Path class to help us accomplish this through a variety of built-in methods:

We start with a path, then extract and output all the various components that make up the path, until we finally retrieve the full path at the end. The result is an output that shows exactly what makes up a path to a file:

It’s important to understand that .NET is looking at the full path when determining whether a path length is too long and, therefore, if a System.IO.PathTooLongException should be thrown.

Most of our code sample logic takes place in the CreateFileByPathLength(int length, char character = 'a') method:

Since all we care about is the length of the path, we’re creating file names with a single character repeated over and over, enough times to result in the full path length being equal to the passed length parameter. The CurrentPath property provides a convenient way of retrieving the full directory (without a file name) of where our executable resides, so we this to test if the length parameter is the same size (or smaller) than the full path length we’d need to actually create a new file.

To create a new file we manually create a new path by combining the CurrentPath with a file name that repeats the passed character parameter as many times as necessary to result in a path length equal to length.

Finally, we output the (shortened) version of the path and the actual path length to the console, before attempting to create a new file at that location. If successful, we output a message, and if creation fails, an exception is thrown and we catch and log that instead.

That’s really all we need for setup, so now we can test this out by attempting to create files with full path lengths of various sizes. At this point it’s worth noting that the official documentation tells us that applications that target .NET Framework 4.6.2 or later will support paths up to 32,767 characters in length (the System.Int16.MaxValue value), unless the operating system returns a COR_E_PATHTOOLONG HRESULT value.

The platform this code is being written and tested on is Windows 10 and the App.config file shows that we’re targeting a .NET Framework that exceeds 4.6.2:

Keeping those things in mind, let’s see what happens when we test out different path length sizes:

As you can see, we’re trying to cover the full spectrum by creating full paths a variety of path lengths. Our logging setup should cover every scenario, so let’s take a look at the output after running this code:

Each call is separated by a blank line, along with the explicit output of the full path length for each attempt, so we can see what lengths work and which fail. As expected, a length of 1 far shorter than the base path length, so that was aborted. 90, 255, and 259 all work just fine, successfully creating new files of various lengths so the full path is equal to those sizes.

The first interesting result we see is at exactly 260 length. In spite of the documentation claim that full paths must exceed 260 length to be a problem, when our path is exactly 260 characters we get a DirectoryNotFoundException. This seems to be some strange quirk, since obviously the directories in this call are no different than they were in the previously successful calls.

Moreover, even though we saw that the .NET Framework 4.7 version we’re running on meets the 4.6.2 or higher requirement, our operating system is disallowed longer paths by default, so 32767 doesn’t work, throwing a System.IO.PathTooLongException our way instead. We also see that, in contradiction to the official documentation, the actual System.IO.PathTooLongException error message indicates that our path length must be less than 260 characters, which could explain the exception when using exactly 260 characters.

One potential fix for this issue, depending on your Windows version, is to enable the use of long paths within the registry. Usual caveat: Don’t make changes to your registry unless you know what you’re doing. We take no responsibility for any damages you may incur.

That said, to enable long paths for some Windows versions you can set the LongPathsEnabled registry entry to 1 (true):

To get the most out of your own applications and to fully manage any and all .NET Exceptions, check out the Airbrake .NET Bug Handler, offering real-time alerts and instantaneous insight into what went wrong with your .NET code, along with built-in support for a variety of popular development integrations including: JIRA, GitHub, Bitbucket, and much more.