Errors
Build the failure value you put inside an Err.
You have decided a method returns Result<T, E>. Now you need something to put in the E.
You can use any type you like — a string, your own record, an enum. This page is about the two types the library ships for when you would rather not write your own.
The two types
public record ErrorCode
{
public ErrorCode(string value);
public string Value { get; }
}
public record Error
{
public Error(ErrorCode code, string message);
public ErrorCode Code { get; }
public string Message { get; }
}An ErrorCode is a short, stable identifier for a kind of failure. An Error is one occurrence of it, with a message a human can read.
Two details that trip people up:
Errornames its code propertyCode, notErrorCode. Read it aserror.Code.Value.Both types declare their constructor explicitly rather than positionally. So you cannot deconstruct them, and you cannot use
withto change a property. Build a new instance instead.
Define your error codes
An error code should not change between one occurrence of a failure and the next. That means defining them up front, not building them at the call site.
As static fields (recommended)
The simplest thing that works. A static class holding every code your application can produce — in your domain layer, if you are following domain-driven design.
Start here. If you outgrow it, the next section is where to go.
From an enum
If you would rather group codes as an enum, mark it [ErrorCodeCatalog] and the source generator writes the codes for you:
This is a generated API with more to it than one line — the naming format, the ToErrorCode() extension for when you only know the member at run time, the using it needs. See Generated error codes.
ErrorCode.FromEnum was obsolete from 6.2.0 and 7.0.0 removed it. So is overriding ErrorCodeFactory.FromEnum to shape what it returns. Mark the enum with [ErrorCodeCatalog] and use the generated members instead. See Deprecations for the migration. FromException is unaffected.
Build an error
Two occurrences, one code. That is the split working as intended: the code is what you branch on and log against, the message is what you show a person.
From a catalog enum
If your codes come from a [ErrorCodeCatalog] enum, the generated Errors factory builds the whole Error in one call:
The message is required here, unlike the code-only form. An Error always carries one.
To turn that straight into a Result, pass it to Result.Err:
Error.FromEnum was obsolete from 6.3.0 and 7.0.0 removed it, along with the Result.Err<TOk>(enum, message) overload that used to collapse the two calls into one. Use the generated factory as above, or value.ToError(message) where you only know the member at run time. See Generated error codes.
From an exception you caught
Both types convert from an exception you already hold, for when you are at a boundary and want a Result rather than a rethrow. That lives on the other page, next to the exceptions themselves — see From an exception you caught.
Where to go next
Exceptions — what the library throws, and when.
Generated error codes — the
[ErrorCodeCatalog]surface in full.Result<T, E> — putting the error to work.
Last updated
Was this helpful?