System.FormatException

A FormatException is thrown when text or a format string is not in the format that a method expects. The most common case is parsing: int.Parse, DateTime.Parse and Guid.Parse all throw it when the text does not match. A malformed format string for string.Format throws it too.

The message names what was wrong, for example The input string 'abc' was not in a correct format.

Minimum version: >= 1.1 >= Core 1.0

Statistics

11
elmah.io logo 5

Common causes

The text did not match the format that the method expects. These are the usual cases.

Parsing text that is not a number

int.Parse and the other Parse methods throw when the text is empty, has spaces or letters, or uses a separator that the current culture does not expect.

var quantity = int.Parse("three");   // FormatException: The input string 'three' was not in a correct format.

Use TryParse for text that comes from users or files:

if (int.TryParse("three", out var quantity))
{
    Console.WriteLine(quantity);
}
else
{
    Console.WriteLine("Please enter a number.");
}

DateTime.Parse accepts many formats, and the result depends on the culture of the machine. Text that works in one culture can fail in another.

var date = DateTime.Parse("not a date");   // FormatException

Parse a known format with TryParseExact and the invariant culture:

var text = "2026-10-06";

if (DateTime.TryParseExact(text, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture,
    System.Globalization.DateTimeStyles.None, out var date))
{
    Console.WriteLine(date);
}

Guid.Parse throws when the text is not a GUID. An id from a query string or a route is a common source.

var id = Guid.Parse("not-a-guid");   // FormatException: Unrecognized Guid format.

Use TryParse and return a clear error for bad ids:

if (!Guid.TryParse("not-a-guid", out var id))
{
    Console.WriteLine("The id is not valid.");
    return;
}

string.Format throws when the format string refers to an argument that was not passed. This is easy to do after you edit a message.

var text = string.Format("{0} of {1}", 3);   // FormatException

Pass every argument, or use string interpolation, where the compiler checks the arguments:

var page = 3;
var pages = 10;
var text = $"{page} of {pages}";

How to fix it and prevent it

Use TryParse and report bad input

The TryParse methods return false instead of throwing. Treat bad input as a normal case and show a message the user can act on.

var input = "12,5";

if (decimal.TryParse(input, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.GetCultureInfo("da-DK"), out var price))
{
    Console.WriteLine(price);
}

Decimal separators, date formats and digits differ between cultures. Use CultureInfo.InvariantCulture for data you store or exchange, and the user's culture only for what you show to them.

var price = decimal.Parse("12.50", System.Globalization.CultureInfo.InvariantCulture);

An interpolated string cannot have a mismatch between placeholders and values, because the compiler checks them. Use composite format strings only when the format comes from a resource.

How to find the bad text

The stack trace shows the parse call. The message contains the text that failed, which makes this one of the easier exceptions to debug:

System.FormatException: The input string 'three' was not in a correct format.
   at System.Number.ThrowFormatException[TChar](ReadOnlySpan`1 value)
   at System.Int32.Parse(String s)
   at Shop.Services.OrderParser.ParseQuantity(String text) in C:\src\Shop\Services\OrderParser.cs:line 11
   at Program.<Main>$(String[] args) in C:\src\Shop\Program.cs:line 4

The message names the text, three, and the line in OrderParser.cs shows the call. Look at where the text came from. A form field, a file or a configuration value that is empty is a common reason. Trim the input, and check the culture if the text looks right but still fails.

Should you catch it?

Usually not. Use a TryParse method, which gives you the same information without an exception. It is faster, and the code is easier to read.

If you must use Parse, catch the exception close to the call, and show the user which input was wrong.

Find FormatException 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

What is the difference between Parse and TryParse?

Parse throws a FormatException when the text is invalid. TryParse returns false and leaves the result at its default value. Use TryParse for input you do not control.

Parsing uses the current culture by default. A date or a decimal number that is valid in one culture is invalid in another. Pass CultureInfo.InvariantCulture or an explicit culture.

It is the older message for a FormatException from parsing. The text did not match the format of the target type. Newer .NET versions include the text in the message.

Yes, when the format string is malformed or refers to an argument index that was not passed, for example "{0} {1}" with only one argument.

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

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

You need 2 things to get this working:

1 - Add an xmlns reference in the root element of your XAML file, to the namespace where your Enum is defined:

<UserControl ...
xmlns:my="clr-namespace:YourEnumNamespace;assembly=YourAssembly"> 

2 - in the Value property of the DataTrigger, use the {x:Static} form:

 <DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="{x:Static my:PingStatus.PING_UNKNOWN}">

Notice that the Enum type must be prefixed with the xmlns prefix you defined above.

Edit:

If your Enum is declared inside a class you need to use the syntax:

{x:Static namespace:ClassName+EnumName.EnumValue}

for example:

{x:Static my:ConfigurationViewModel+PingStatus.PING_UNKNOWN}

By Fede. Read the original answer on Stack Overflow.

Not sure if still relevant, but I recently ran into this same issue and was able to solve it by calling a different method to add the header information:

var http = new HttpClient();
http.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=XXX");

By Antonio. Read the original answer on Stack Overflow.

You need to add the Time separator to your string. Try this:

TimeSpan ts = XmlConvert.ToTimeSpan("PT72H");

See the duration specification - http://www.w3.org/TR/xmlschema-2/#duration

3.2.6.1 Lexical representation
The lexical representation for duration is the [ISO 8601] extended format PnYn MnDTnH nMnS, where nY represents the number of years, nM the number of months, nD the number of days, 'T' is the date/time separator, nH the number of hours, nM the number of minutes and nS the number of seconds. The number of seconds can include decimal digits to arbitrary precision.

Edit/Update based on comments

As there was some question as to why the string P2M2W5D would not be considered a valid TimeSpan since W is part of the ISO 8601 standard, I wanted to add this update so that if someone runs across that issue they don't have to read through the comments to get the answer. The issue, both for the original string in question P72H and P2M2W5D is that the string must conform to the W3C XML Schema (see the documentation for XmlConvert.ToTimeSpan). When we look at the W3C XML Schema (link above), it references back to the ISO 8601 standard, and in particular to section 5.5.3.2.1 which gives the reason why W is not a valid character in the XML Schema:

Since weeks have no defined carry-over point (52 or 53), weeks should not be used in these applications

By pstrjds. Read the original answer on Stack Overflow.

I've got it. And yes, it's a bug.

The problem is that there are two levels of string.Format going on here.

The first level of formatting is something like:

string template  = string.Format("Expected: {0}; Actual: {1}; Message: {2}",
                                 expected, actual, message);

Then we use string.Format with the parameters you've supplied:

string finalMessage = string.Format(template, parameters);

(Obviously there's cultures being provided, and some sort of sanitization... but not enough.)

That looks fine - unless the expected and actual values themselves end up with braces in, after being converted to a string - which they do for Size. For example, your first size ends up being converted to:

{Width=0, Height=0}

So the second level of formatting is something like:

string.Format("Expected: {Width=0, Height=0}; Actual: {Width=1, Height=1 }; " +
              "Message = Failed expected {0} actually is {1}", struct1, struct2);

... and that's what's failing. Ouch.

Indeed, we can prove this really easily by fooling the formatting to use our parameters for the expected and actual parts:

var x = "{0}";
var y = "{1}";
Assert.AreEqual<object>(x, y, "What a surprise!", "foo", "bar");

The result is:

Assert.AreEqual failed. Expected:<foo>. Actual:<bar>. What a surprise!

Clearly broken, as we weren't expecting foo nor was the actual value bar!

Basically this is like a SQL injection attack, but in the rather less scary context of string.Format.

As a workaround, you can use string.Formatas StriplingWarrior suggests. That avoids the second level of formatting being performed on the result of formatting with the actual/expected values.

By Jon Skeet. Read the original answer on Stack Overflow.

Try this instead:

Assert.That(() => Int32.Parse("abc"), Throws.Exception.TypeOf<FormatException>());

Basically you need to pass a delegate to Assert.That, just like the documentation in your link states (note that I've used a lambda expression here, but it should be the same).

By Klaus Byskov Pedersen. Read the original answer on Stack Overflow.