How to Fix System.IO.IOException: The configured user limit on the number of inotify instances has been reached

Date: 2024-09-20 | create | tech | dotnet | asp-dotnet | fsharp | csharp | linux | unix |

I recently ran into a problem with one of my dotnet projects - TravelMap. It started throwing an exception System.IO.IOException: The configured user limit (8192) on the number of inotify instances has been reached which crashed my app and blocked it from spinning up its webserver.

Here I'll share how I resolved it so hopefully it can unblock you as well.

App Setup and Overview

First a bit of context on the app itself and how it's hosted so you can understand the environment it was running in and get a better idea if this exception / fix is relevant to your app setup or not.

  • App - ASP.NET webapp written in F#. Uses standard Host.CreateDefaultBuilder()
  • Hosting - Docker container running on Railway Linux Server (Hosting provider doesn't matter but container and Linux/Unix does)

For more information on TravelMap and how it's built, checkout the TravelMap project page

System.IO.IOException: inotify instances reached

The System IOException was thrown when my container tried to startup. On debugging it appeared that the container failed in configuration during startup.

The full exception message:

Unhandled exception. System.IO.IOException: The configured user limit (8192) on the number of inotify instances has been reached, or the per-process limit on the number of open file descriptors has been reached.

According to Stack Overflow this can often happen when running dotnet on Linux / Unix and is often caused by too many file watchers on a configuration file. This matched up with what I was doing and my exception's logs so is likely what caused this issue.

Fixing the Exception

One of the recommended ways to fix this exception is to set reloadOnChange=false in the ConfigurationBuilder for your file. This will prevent the builder from opening up additional file watchers and thus will not run into this issue.

I did this and it fixed my problem so seems to work.

My ConfigurationBuilder after the fix:

let fetchConfiguration (environment_name : string) =
    let targetConfigurationFile = (
        if environment_name.ToLower() = "development" 
            then "appsettings.Development.json" 
            else "appsettings.json")

    let configurationRoot = (
        (ConfigurationBuilder())
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile(targetConfigurationFile, false, reloadOnChange=false)
            .Build())

    let root = configurationRoot.Get<AppConfiguration>()
    root

Note: This fix works by preventing new filewatchers on configuration files - this means dotnet will not reload if this file changes. This is fine for my case because I know my configuration will never change during the lifecycle of my app - if there is a change, I would deploy a new container. For some cases this may not work (like local hotreloading) so use with discretion.

Next

This unblocked me and was pretty simple so I decided to log this for posterity in the hope that it helps others and saves me time when I inevitably run into this again. I've gone ahead and added this fix into CloudSeed (my F# project boilerplate for webapps) so that I can avoid this when spinning up new apps.

Want to get started building webapps with F#? Spin up a fullstack F# web app in 10 minutes with CloudSeed

If you liked this post you might also like:

Want more like this?

The best / easiest way to support my work is by subscribing for future updates and sharing with your network.