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
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>();
}
}
Configuration that is missing in static code
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);
}
}
Initialization order and dependencies between static fields
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}");
}
}
Keep static initializers simple
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.
Fix it and restart
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 trialRelated exceptions
- FileNotFoundException is a common inner exception, when a static initializer reads a file.
- TypeLoadException is thrown when a type cannot be loaded at all.
- NullReferenceException is another common inner exception, from fields that are used before they are set.
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.
How do I find the real exception?
Read InnerException. Most loggers include it. The elmah.io client does too, so the original error is in the details of the message.
Is a static constructor a bad idea?
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.
What is the difference from TypeLoadException?
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:
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.
Update Nuget Package
https://www.nuget.org/packages/System.Threading.Tasks.Extensions/
will solve your problem
By Jitendra Morya. 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.
Source: Stack Overflow