# Exceptions in C#

When something goes wrong at run time, C# throws an exception, and the program crashes unless code catches it. Prevent what you can check for; catch what you can't, most specific type first; and throw your own when a method can't do what it's asked.

Apprentice · C# · Updated November 3, 2026

## After this lesson you can

- Catch an exception with try and catch, catching specific exception types before general ones
- Prevent errors you can check for with if or TryParse, and keep try and catch for those you can't
- Throw an exception when a method is asked to do something it can't

## Key takeaways

- An exception that no code catches crashes the program. Put risky code in a `try`, and handle the failure in a `catch`.
- C# runs the first `catch` that matches, so put `FileNotFoundException` before `IOException`. Catching `Exception` itself is a last resort.
- If you can check for a problem with an `if` or `TryParse`, check instead of catching; keep `try` and `catch` for what you can't check, such as files.
- A `finally` block runs after the `try`, whether an exception was thrown or not.
- When your method is asked to do something it can't, `throw` an exception such as `ArgumentException` instead of carrying on with bad data.

Some problems can't be seen until a program runs. A user types `abc` where you asked for a number. A file you need has been deleted. Another program has the file open. These are **run-time errors**, and the compiler can't warn you about them.

When one happens, C# creates an **exception**: an object that describes what went wrong, such as a `FormatException` or a `FileNotFoundException`. Then it **throws** it. If no code **catches** the exception, the program crashes.

## An exception nobody catches

```csharp
int quantity = int.Parse("abc");
Console.WriteLine($"You ordered {quantity}");
```

```text
Unhandled exception. System.FormatException: The input string 'abc' was not in a correct format.
```

The second line never runs. The exception stops the program in its tracks, and C# prints the exception's type, its **message**, and a list of the methods it passed through (the *stack trace*), which tells you where to look.

You've seen this before: an index past the end of an array, `Dequeue` on an empty queue. Each was an exception.

## try and catch

To handle an exception instead of crashing, put the risky code in a **`try`** block, and say what to do if it fails in a **`catch`** block:

```csharp
string input = "abc";

try
{
    int quantity = int.Parse(input);
    Console.WriteLine($"You ordered {quantity}");
}
catch (FormatException ex)
{
    Console.WriteLine($"Sorry: {ex.Message}");
}

Console.WriteLine("The program carries on");
```

```text
Sorry: The input string 'abc' was not in a correct format.
The program carries on
```

When `int.Parse` throws, the rest of the `try` block is skipped, and C# jumps to the `catch` block whose type matches. `ex` is the exception object, and `ex.Message` describes what went wrong. After the `catch`, the program carries on as normal.

If nothing goes wrong, the `catch` block is skipped entirely.

## Catching specific types

Catch the exceptions you **expect** and know what to do about. Reading a file can fail in different ways, and each deserves its own message:

```csharp
try
{
    string text = File.ReadAllText("student_grades.csv");
    Console.WriteLine(text);
}
catch (FileNotFoundException)
{
    Console.WriteLine("There's no student_grades.csv. Check the file name.");
}
catch (IOException ex)
{
    Console.WriteLine($"The file couldn't be read: {ex.Message}");
}
```

```text
There's no student_grades.csv. Check the file name.
```

C# tries the `catch` blocks **in order**, and runs the first one that matches. A `FileNotFoundException` **is an** `IOException` (exceptions use inheritance too), so the specific one must come first. Here the `IOException` block handles everything else that can go wrong with a file, such as another program having it locked. (When a `catch` block doesn't use the exception, you can leave out the variable name, as the first one does.)

At the very top of the family is **`Exception`**, which matches every exception. Put a more specific catch after it, and C# refuses, since the specific one could never run:

```csharp
try
{
    string text = File.ReadAllText("student_grades.csv");
}
catch (Exception)
{
    Console.WriteLine("Something went wrong");
}
catch (FileNotFoundException)
{
    Console.WriteLine("There's no student_grades.csv");
}
```

```text
error CS0160: A previous catch clause already catches all exceptions of this or a super type ('Exception')
```

Catching `Exception` itself is a last resort, for the very top of a program or a log of errors you didn't expect. A `catch (Exception)` around everything hides bugs you'd want to know about.

## finally

A **`finally`** block runs after the `try`, whether an exception was thrown or not, and even when it was caught:

```csharp
try
{
    Console.WriteLine("Saving...");
    int.Parse("abc");
}
catch (FormatException)
{
    Console.WriteLine("Couldn't save");
}
finally
{
    Console.WriteLine("Done");
}
```

```text
Saving...
Couldn't save
Done
```

It's for cleaning up, such as closing a file. You'll rarely need it, because `using` closes files and connections for you even when an exception is thrown, as you'll see in *Reading a File in C#*.

## Prevent what you can check

Exceptions are for the **exceptional**. If you can check for a problem with an `if`, check:

| Instead of catching | Check first |
|---|---|
| `IndexOutOfRangeException` | `if (index < scores.Length)` |
| `DivideByZeroException` | `if (count > 0)` |
| `FormatException` from `int.Parse` | `int.TryParse`, which returns `false` instead of throwing |

```csharp
string[] inputs = { "12", "abc", "7" };

foreach (string input in inputs)
{
    if (int.TryParse(input, out int quantity))
    {
        Console.WriteLine($"Ordered {quantity}");
    }
    else
    {
        Console.WriteLine($"'{input}' isn't a number");
    }
}
```

```text
Ordered 12
'abc' isn't a number
Ordered 7
```

Checking is clearer, and much faster than throwing and catching. Keep `try` and `catch` for what you **can't** check beforehand. Files are the classic case: even after `File.Exists` says yes, another program could delete or lock the file a moment later. So code that reads a file always goes in a `try`.

## Throwing your own

Your own methods can throw exceptions too. When a method is asked to do something it can't, such as an order of zero items, **`throw`** an exception rather than carrying on with bad data:

```csharp
try
{
    AddToOrder("Coffee", 0);
}
catch (ArgumentException ex)
{
    Console.WriteLine(ex.Message);
}

void AddToOrder(string item, int quantity)
{
    if (quantity < 1)
    {
        throw new ArgumentException("Quantity must be at least 1.", nameof(quantity));
    }
    Console.WriteLine($"Added {quantity} x {item}");
}
```

```text
Quantity must be at least 1. (Parameter 'quantity')
```

`throw` stops the method at once, and the exception travels back to whichever code called it, until some `catch` handles it. Pick the type that says what went wrong:

| Exception | Throw it when |
|---|---|
| `ArgumentException` | A parameter's value isn't allowed |
| `ArgumentNullException` | A parameter is `null` and mustn't be |
| `InvalidOperationException` | The object can't do that right now, such as starting a ride that's already started |

## Check yourself

3 questions to try on the lesson page.

## So what

Check for what you can, catch what you can't, and throw when your own code is asked to do the impossible. An exception should be a clear message about something truly unexpected, never a crash your users have to report.

## Key terms

- [Exception](https://www.ask-codey.com/glossary/exception-c-sharp)
- [try Block](https://www.ask-codey.com/glossary/try-block-c-sharp)
- [catch Block](https://www.ask-codey.com/glossary/catch-block-c-sharp)
- [finally Block](https://www.ask-codey.com/glossary/finally-block-c-sharp)
- [throw](https://www.ask-codey.com/glossary/throw-c-sharp)

## Cheat sheets

- [Exceptions in C#](https://www.ask-codey.com/cheat-sheets/exceptions-in-csharp-cheat-sheet)

Source: https://www.ask-codey.com/lessons/exceptions-in-csharp
