> For the complete documentation index, see [llms.txt](https://draekien-industries.wpei.me/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://draekien-industries.wpei.me/using-the-library/errors-and-exceptions.md).

# Errors and Exceptions

## Built in Error Types

Waystone.Monads provides a set of built in error types for convenience in the case you do not wish to write your own.

```csharp
record ErrorCode(string Value);
record Error(ErrorCode ErrorCode, string Message);
```

### ErrorCode

The `ErrorCode` type is a short code representing an error type in the application. These codes should not change between occurrence to occurrence of the same error type. It is recommended to predefine your error codes.

#### Static Error Codes (recommended)

The simplest way of defining your error codes is to create a static `ErrorCodes` class that contains the list of error codes that may be encountered during the lifecycle of your application. This class would normally live inside your domain layer if you are following domain driven design.

```csharp
public static class ErrorCodes
{
    public static readonly ErrorCode InputMissing = new("input.missing");
    public static readonly ErrorCode InputMalformed = new("input.malformed");
    public static readonly ErrorCode InputOutOfRange = new("input.out_of_range");
}
```

#### Error Code from Enum

You may want to use enums to define and organise your error codes, and then create `ErrorCode` instances during runtime from these enums. A factory method has been provided to facilitate this approach.

```csharp
public enum InputErrors
{
    Missing = 1,
    Malformed = 2,
    OutOfRange = 3
}

public enum RegexErrors // etc.

var errorCode = ErrorCode.FromEnum(InputErrors.Missing); // "InputErrors.Missing"
```

{% hint style="danger" %}
**`ErrorCode.FromEnum` is obsolete from 6.2.0 and is removed in 7.0.0.** So is overriding `ErrorCodeFactory.FromEnum` to shape what it returns. Mark the enum with `[ErrorCodeCatalog]` instead and use the members that generates — `OrderErrorCatalog.Codes.NotFound` where you can name the member, or the generated `ToErrorCode()` extension where you cannot. See [Deprecations](/using-the-library/deprecations.md) for the migration and [Generated error codes](/using-the-library/generated-error-codes.md) for the `Format` that replaces a factory override. `FromException` is unaffected.
{% endhint %}

#### Error Code from Exception

You may want to use the exception type itself as the source of your error codes when they are caught during runtime. A factory method has been provided to facilitate this approach.

{% hint style="warning" %}
This approach may introduce inconsistencies in your error codes. It also does not work well if you are raising errors that are not caused by exceptions elsewhere in your application.
{% endhint %}

```csharp
try
{
    // do work
}
catch (SqlException e)
{
    var errorCode = ErrorCode.FromException(e); // "Err.Sql"
}
```

{% hint style="info" %}
If you want to customise the error code that is generated from the `Exception`, you can provide your own instance of `ErrorCodeFactory` to the global `MonadOptions` and override the `FromException` method.
{% endhint %}

### Error

The `Error` type captures an instance of an error associated with a specific `ErrorCode`. Use it to provide human-readable information about the error instance that occurred during runtime.

{% hint style="info" %}
You must define an `ErrorCode` before creating an `Error`
{% endhint %}

```csharp
Error error1 = new(ErrorCodes.InputMalformed, "Expected an absolute URI but received a relative URI");
Error error1 = new(ErrorCodes.InputMalformed, "Failed to parse input as a number");
```

#### Error from Enum

If your error codes come from enums, you can create the `Error` in one call. This uses [#error-code-from-enum](#error-code-from-enum "mention") under the hood to generate the `ErrorCode`.

```csharp
public enum InputErrors
{
    Missing = 1,
    Malformed = 2,
    OutOfRange = 3
}

Error error = Error.FromEnum(InputErrors.Malformed, "Failed to parse input as a number");
//    ^? ErrorCode: "InputErrors.Malformed", Message: "Failed to parse input as a number"
```

{% hint style="info" %}
The message is required here, unlike `ErrorCode.FromEnum` which takes only the enum value. An `Error` always carries a human-readable message.
{% endhint %}

To create a `Result` directly from an enum, use `Result.Err<TOk>(enum, message)`. See [Core Functionality](/using-the-library/core-functionality.md#creation).

#### Error from Exception

You may want to create errors on the fly when catching exceptions without having to first define your error code. A factory method has been provided to facilitate this approach. It uses [#error-code-from-exception](#error-code-from-exception "mention") under the hood to generate the `ErrorCode`.

{% hint style="warning" %}
This approach may introduce inconsistencies in your error codes. It also does not work well if you are raising errors that are not caused by exceptions elsewhere in your application.
{% endhint %}

```csharp
try
{
    // do work
}
catch (SqlException e)
{
    var error = Error.FromException(e);
    //  ^? ErrorCode: "Err.Sql", Message: e.Message
}
```

If you want to customise the error code that is generated from the `Exception`, you can provide your own instance of `ErrorCodeFactory` to the global `MonadOptions` and override the `FromException` method. See [#error-code-from-exception](#error-code-from-exception "mention") for an example.

## Custom Exceptions

This library contains some custom exceptions that describe certain scenarios.

### UnwrapException

An exception that is thrown when attempting to [Core Functionality](/using-the-library/core-functionality.md#unwrap) an `Option<T>` or a `Result<T, E>` when they are in their `None` or `Err` states, or when attempting to [Result\<T, E>](/using-the-library/result-of-t-and-e.md#unwraperr) on a `Result<T, E>` when it is in it's `Ok` state.

{% hint style="info" %}
Always check the monad's state before performing an `Unwrap` or `UnwrapErr` to avoid encountering this exception.
{% endhint %}

### UnmetExpectationException

An exception that is thrown when when invoking [Core Functionality](/using-the-library/core-functionality.md#expect) on an `Option<T>` or a `Result<T, E>` when they are in their `None` or `Err` states, or when invoking [Result\<T, E>](/using-the-library/result-of-t-and-e.md#expecterr) on a `Result<T, E>` when it is in it's `Ok` state.
