System.TypeInitializationException

A TypeInitializationException is thrown when a static constructor or a static field initializer throws. The runtime wraps the original exception in this one, and the message only says The type initializer for 'X' threw an exception.

The type is never usable after that. Every later access to the class throws the same exception, so one failed initializer can show up many times in a log, long after the first failure.

Minimum version: >= 1.1 >= Core 1.0

Statistics

16
elmah.io logo 34

Common causes

The wrapper is never the problem. The original exception is in InnerException, and the stack trace has the line of the initializer. Typical causes:

A static field that reads something that can fail

A static initializer that opens a file, reads configuration or connects to a service runs the first time the class is used, and the code that triggers it has no idea that it can fail.

public static class ExchangeRates
{
    public static readonly Dictionary<string, decimal> Rates = Load();

    static Dictionary<string, decimal> Load()
    {
        var json = File.ReadAllText("rates.json");
        return new Dictionary<string, decimal>();
    }
}

Load the data lazily, so the failure happens in a place that can handle it, and does not poison the type:

public static class ExchangeRates
{
    private static Dictionary<string, decimal> _rates;

    public static Dictionary<string, decimal> GetRates()
    {
        return _rates ??= Load();
    }

    static Dictionary<string, decimal> Load()
    {
        var json = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "rates.json"));
        return new Dictionary<string, decimal>();
    }
}

Static fields that read environment variables or settings throw when the value is missing, and that is more likely in a new environment. It fails in the first request, and not when the application starts.

public static class Endpoints
{
    public static readonly Uri Prices = new Uri(Environment.GetEnvironmentVariable("PRICES_URL"));
}

Read the settings through dependency injection and the options pattern, and validate them at startup. Then the message says which value is missing:

public class EndpointOptions
{
    public string PricesUrl { get; set; }
}

public class EndpointValidator
{
    public Uri GetPricesUri(EndpointOptions options)
    {
        if (string.IsNullOrEmpty(options.PricesUrl))
            throw new InvalidOperationException("PricesUrl is not configured.");

        return new Uri(options.PricesUrl);
    }
}

Static fields run in the order they are written. A field that uses another one that is declared later sees the default value, null, and throws. Two classes that use each other in their static constructors can also see each other half-initialized.

public static class Defaults
{
    public static readonly string Currency = Prefix.ToUpper();   // Prefix is still null here
    public static readonly string Prefix = "dkk";
}

Declare the fields in the order they are used, or compute the values in one place:

public static class Defaults
{
    public static readonly string Prefix = "dkk";
    public static readonly string Currency = Prefix.ToUpper();
}

How to fix it and prevent it

Read the InnerException first

The message of the wrapper is always the same, so skip it. The inner exception is the real error, and its stack trace ends in the static constructor, shown as ..cctor.

static class Rates
{
    public static readonly int Count = int.Parse("x");
}

public void Show()
{
    try
    {
        _ = Rates.Count;
    }
    catch (TypeInitializationException e)
    {
        Console.WriteLine($"{e.TypeName} failed: {e.InnerException?.Message}");
    }
}

Do only things that cannot fail in a static initializer, such as creating objects and setting constants. Move file, network and configuration work to code that is called on purpose, where you can handle errors and retry.

The type stays broken for the life of the process, so fixing the cause is not enough. Deploy the fix, which restarts the process, and make sure the error that started it is in the log, not only the later ones.

How to read the stack trace

The outer exception is the wrapper, and the real error comes after --->:

System.TypeInitializationException: The type initializer for 'Shop.Services.ExchangeRates' threw an exception.
 ---> System.IO.FileNotFoundException: Could not find file 'C:\src\Shop\bin\Debug\net10.0\rates.json'.
File name: 'C:\src\Shop\bin\Debug\net10.0\rates.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.ExchangeRates.Load() in C:\src\Shop\Services\ExchangeRates.cs:line 7
   at Shop.Services.ExchangeRates..cctor() in C:\src\Shop\Services\ExchangeRates.cs:line 4
   --- End of inner exception stack trace ---
   at Program.<Main>$(String[] args) in C:\src\Shop\Program.cs:line 4

The inner exception is a FileNotFoundException for rates.json. The frames show that ExchangeRates.Load on line 7 was called from the static constructor, ..cctor, on line 4. The line at the bottom, Program.cs line 4, is only the first code that used the class. Fix the file problem, and the type loads.

Should you catch it?

Catching it does not bring the type back, since every use of the class throws again. Catch it at the place where you can log the inner exception and show an error.

Because later uses repeat the same exception, find the first one in the log. It has the stack trace of the real error.

Find TypeInitializationException 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 do I get the same TypeInitializationException again and again?

The runtime remembers that the initializer failed, and throws the same exception for every use of the type. Only a restart of the process makes it try again.

Read InnerException. Most loggers include it. The elmah.io client does too, so the original error is in the details of the message.

It is fine for simple setup. It becomes a problem when it does work that can fail, because the failure ends up in code that does not expect it and cannot recover.

A TypeInitializationException means that the type was found but its static initializer threw. A TypeLoadException means that the runtime could not load the type at all.

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 TypeInitializationException for you. For example:

AI chat
Find the most frequent TypeInitializationException 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

In my case, I got the issue after upgrading to version 4.5.4 and tried @user2713341 answer. It didn't work but put me in the right direction.

My project had no bindings for this library, so I added the binding and it worked

<dependentAssembly>
  <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
</dependentAssembly>

and it worked.

Note that it should be assembly version 4.2.0.1 even though the package version is 4.5.4.

By Keyjote. Read the original answer on Stack Overflow.

Another possible reason: the app.config has duplicate sections.

By Stagg. Read the original answer on Stack Overflow.

A possible reason: init a static dictionary with duplicated keys.

By Robin Qiu. Read the original answer on Stack Overflow.

The response from @Keyjote was at the root of the solution for me, but rather than cherry-picking the assemblies, I was able to just reinstall. This seemed to automatically repair the app.config file.

Tools -> Nuget Packet Manager -> Packet Manager Console

Update-Package -reinstall -Project <your project name>

This way you don't need to mess with the syntax or have to figure out the PublicKeyToken values.

If you want to do it for the whole solution, you can omit the -Project <> parameter.

By Hambone. Read the original answer on Stack Overflow.