DiagnosableExceptions is most useful when errors are not just technical failures, but meaningful events in the life of the system. Below are common patterns where the library brings clarity and structure.
When creating a value object, invalid states must be rejected.
public static Amount From(decimal value, Currency currency)
{
if (value < 0)
{
throw InvalidAmountException.NegativeValue(value, currency);
}
return new Amount(value, currency);
}Here:
- the domain rule is explicit
- the exception represents a precise invariant violation
- documentation describes the rule and diagnostics
This keeps domain code expressive and self-explanatory.
User or external inputs may be invalid, but not exceptional in the technical sense.
public TryOutcome<Amount> TryCreateAmount(decimal value, string currencyCode)
{
if (!Currency.TryParse(currencyCode, out var currency))
{
return TryOutcome<Amount>.Failure(
InvalidAmountException.UnknownCurrency(currencyCode));
}
return TryOutcome<Amount>.Success(new Amount(value, currency));
}Errors are:
- captured
- transportable
- diagnosable
without interrupting the flow.
Operations between domain objects often have semantic constraints.
public Amount Add(Amount other)
{
if (Currency != other.Currency)
{
throw InvalidAmountOperationException.CurrencyMismatch(this, other);
}
return new Amount(Value + other.Value, Currency);
}The code reads like domain language, while the error remains structured and documented.
In batch processing, many items may fail independently.
foreach (var line in file)
{
var result = TryParseAmount(line);
if (result.IsFailure)
{
Log(result.Exception);
continue;
}
Process(result.Value);
}Errors are:
- collected
- logged with full diagnostics
- not disruptive to the entire process
When interacting with external systems:
- data may be inconsistent
- formats may change
- assumptions may break
Using diagnosable exceptions helps distinguish:
- domain issues
- input issues
- system or transformation issues
Diagnostics guide where investigation should start.
Complex validations often involve multiple checks.
var result = ValidateAmount(amount)
.Bind(CheckCurrency)
.Bind(CheckLimits);Each failure can carry a diagnosable exception, keeping the model consistent while avoiding uncontrolled throwing.
Because exceptions carry structured diagnostics, logs become more useful:
- stable error codes
- meaningful short messages
- documented causes
Support teams can relate runtime events to documented error cases.
DiagnosableExceptions shines when:
| Situation | Benefit |
|---|---|
| Domain invariants | Clear semantic violations |
| Validation | Errors as data |
| Operations | Readable domain code |
| Batch processing | Non-blocking error handling |
| Integration | Better troubleshooting |
| Support | Structured knowledge |
The library helps you express not just that something failed — but what it means, why it might have happened, and where to look.
Previous section : Writing Errors Guide | Next section: Best Practices