Exception Properties in C#
Vaibhav • September 10, 2025
In the previous article, we explored how multiple catch blocks allow us to handle different types of exceptions with precision. Now it’s time to dive deeper into the structure of exceptions themselves. Every exception in C# carries useful information - not just the error message, but also metadata that helps us understand what went wrong, where, and why. These are called exception properties, and learning to use them effectively is a key part of writing robust, debuggable applications.
What Are Exception Properties?
When an exception is thrown, it’s not just a signal - it’s an object. That object contains properties that
describe the error in detail. These properties are part of the System.Exception
class, which is the base class for all exceptions in C#. Whether you’re dealing with a FileNotFoundException
, a DivideByZeroException
,
or a custom exception, you can inspect these properties to understand the error better.
Exception properties are especially useful for logging, debugging, and building user-friendly error messages. They help you trace the source of the problem without guessing.
Key Properties of Exception
Let’s look at the most commonly used properties of the Exception
class:
Message
- A human-readable description of the error.StackTrace
- A string that shows the call stack at the time the exception was thrown.Source
- The name of the application or object that caused the error.TargetSite
- The method that threw the exception.InnerException
- Another exception that caused the current one (used for exception chaining).HelpLink
- A URL to a help file associated with the exception (optional).
Using Exception Properties in Practice
Here’s a simple example that throws and catches an exception, then prints its properties:
try
{
int x = 0;
int result = 10 / x;
}
catch (Exception ex)
{
Console.WriteLine("Message: " + ex.Message);
Console.WriteLine("StackTrace: " + ex.StackTrace);
Console.WriteLine("Source: " + ex.Source);
Console.WriteLine("TargetSite: " + ex.TargetSite);
}
This code attempts to divide by zero, which throws a DivideByZeroException
. The
catch block then prints out the exception’s properties. Let’s break it down:
- Message: Tells you what went wrong - in this case, “Attempted to divide by zero.”
- StackTrace: Shows the exact sequence of method calls that led to the error.
- Source: Usually the name of the assembly or class where the error occurred.
- TargetSite: Points to the method that threw the exception.
Understanding StackTrace
The StackTrace
property is one of the most valuable tools for debugging. It
shows the path your code took before the exception was thrown. Each line in the stack trace represents a method
call, starting from the method that threw the exception and going back up the call stack.
Message: Attempted to divide by zero.
StackTrace:
at Program.Main() in Program.cs:line 10
This tells you that the error occurred in the Main
method, on line 10 of Program.cs
. If your application has multiple layers - UI, business logic, data
access - the stack trace helps you pinpoint which layer failed.
Using InnerException for Chained Errors
Sometimes one exception causes another. For example, a database error might trigger a data access exception. In
such cases, you can use the InnerException
property to preserve the original
error:
try
{
SaveToDatabase();
}
catch (SqlException ex)
{
throw new DataAccessException("Failed to save data.", ex);
}
Later, when you catch the DataAccessException
, you can inspect its InnerException
to see the original SqlException
:
catch (DataAccessException ex)
{
Console.WriteLine("Outer: " + ex.Message);
Console.WriteLine("Inner: " + ex.InnerException?.Message);
}
This pattern is called exception wrapping, and it’s a best practice for preserving context across layers.
TargetSite and Source
The TargetSite
property tells you which method threw the exception. This is
useful when you’re catching exceptions at a higher level and want to know where they originated.
catch (Exception ex)
{
Console.WriteLine("Thrown by: " + ex.TargetSite.Name);
}
The Source
property usually contains the name of the assembly or class. It’s
helpful for logging and diagnostics, especially in large applications.
HelpLink - Optional but Useful
You can set the HelpLink
property to point to a URL or documentation page that
explains the error. This is rarely used in small projects but can be helpful in libraries or APIs:
var ex = new Exception("Invalid configuration.");
ex.HelpLink = "https://docs.myapp.com/errors/config";
Consumers of your API can then use this link to learn more about the error and how to fix it.
Custom Exception Properties
You can add your own properties to custom exceptions to carry domain-specific data. For example:
public class ValidationException : Exception
{
public string FieldName { get; }
public ValidationException(string fieldName, string message)
: base(message)
{
FieldName = fieldName;
}
}
This lets you pass structured information to the caller. You can then inspect it like any other property:
catch (ValidationException ex)
{
Console.WriteLine($"Error in field {ex.FieldName}: {ex.Message}");
}
This pattern is especially useful in form validation, API responses, and business rule enforcement.
Logging Exception Properties
When logging exceptions, it’s important to include all relevant properties. A good logging statement might look like this:
catch (Exception ex)
{
logger.LogError($"Exception: {ex.GetType().Name}");
logger.LogError($"Message: {ex.Message}");
logger.LogError($"Source: {ex.Source}");
logger.LogError($"TargetSite: {ex.TargetSite}");
logger.LogError($"StackTrace: {ex.StackTrace}");
if (ex.InnerException != null)
{
logger.LogError($"InnerException: {ex.InnerException.Message}");
}
}
This gives you a complete picture of the error, which is invaluable for debugging and support.
Best Practices for Using Exception Properties
Exception properties are powerful, but they should be used thoughtfully. Here are some guidelines:
- Always log the
Message
andStackTrace
. - Use
InnerException
to preserve context when wrapping exceptions. - Inspect
TargetSite
andSource
for diagnostics. - Use custom properties to pass structured data in domain-specific exceptions.
- Consider setting
HelpLink
in public APIs or libraries.
Treat exceptions as rich data objects. Don’t just catch and ignore - inspect, log, and use their properties to understand and improve your code.
Summary
Exception properties are the key to understanding errors in C#. They provide detailed information about what
went wrong, where it happened, and why. By inspecting properties like Message
,
StackTrace
, Source
, TargetSite
, and InnerException
, you can diagnose
problems quickly and accurately. Custom exceptions can carry even more context, making your error handling
smarter and more expressive.
In the next article, we’ll explore Throwing Exceptions - how to raise errors intentionally, how to choose the right exception type, and how to write throw statements that are clear, informative, and maintainable.