> ## Documentation Index
> Fetch the complete documentation index at: https://ancplua.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# ErrorOrX Overview

> Discriminated unions for .NET with fluent error handling and ASP.NET Core integration

ErrorOrX provides discriminated union types for .NET with a fluent API for error handling and automatic ASP.NET Core Minimal API integration.

## Packages

| Package               | Purpose                                    |
| --------------------- | ------------------------------------------ |
| `ErrorOrX`            | Runtime library with `ErrorOr<T>` type     |
| `ErrorOrX.Generators` | Source generator for Minimal API endpoints |

## Installation

```bash theme={null}
dotnet add package ErrorOrX.Generators
```

<Note>
  `ErrorOrX.Generators` automatically includes `ErrorOrX` as a dependency.
</Note>

<Note>
  **v3.0.1+**: Fixed automatic `PrivateAssets=all` issue. No manual `.csproj`
  editing required.
</Note>

## What's New

<Accordion title="Recent Changes (v3.1+)">
  **Performance:**

  * Fixed N+1 symbol lookup performance issue. `ErrorOrContext` is now created once per compilation instead of once per endpoint, reducing symbol lookups from N x 90 to 90 for N endpoints.

  **API Versioning:**

  * Full support for `Asp.Versioning.Http` with `[ApiVersion]`, `[MapToApiVersion]`, and `[ApiVersionNeutral]` attributes.
  * New diagnostics EOE050-EOE055 for versioning issues.

  **New Diagnostics:**

  * EOE055: Warning when multiple method parameters bind to the same route parameter name.

  **Bug Fixes:**

  * Fixed `NullReferenceException` when error type inference encountered local variables.
  * Added null guards on `AttributeClass` for malformed attributes.
  * Changed route parameter binding to "first wins" semantics for deterministic behavior.
</Accordion>

## Quick Start

```csharp theme={null}
using ErrorOr;

// Define an endpoint handler
public static class TodoEndpoints
{
    [Get("/todos/{id}")]
    public static ErrorOr<Todo> GetById(Guid id)
    {
        var todo = _db.Find(id);
        if (todo is null)
            return Error.NotFound("Todo.NotFound", $"Todo {id} not found");
        return todo;
    }
}

// Register services (Program.cs)
builder.Services.AddErrorOrEndpoints()
    .UseJsonContext<AppJsonSerializerContext>()
    .WithCamelCase()
    .WithIgnoreNulls();

// Map endpoints
app.MapErrorOrEndpoints();
```

The generator produces:

* `MapErrorOrEndpoints()` extension method
* Typed `Results<...>` union for OpenAPI
* Smart parameter binding (infers `[FromBody]`/`[FromServices]` based on HTTP method and type)
* Middleware fluent calls (preserves `[Authorize]`, `[EnableRateLimiting]`, etc.)
* JSON serialization context (AOT-compatible)

## Core Types

### ErrorOr\<T>

A discriminated union that holds either a value of type `T` or one or more `Error` instances.

```csharp theme={null}
ErrorOr<User> result = GetUser(id);

// Check state
if (result.IsError)
{
    // Handle errors
    foreach (var error in result.Errors)
        Console.WriteLine($"{error.Code}: {error.Description}");
}
else
{
    // Use value
    var user = result.Value;
}
```

### Fluent API

| Method     | Purpose                     |
| ---------- | --------------------------- |
| `Then()`   | Chain operations on success |
| `Else()`   | Provide fallback on error   |
| `Match()`  | Transform to result         |
| `Switch()` | Execute side effects        |
| `FailIf()` | Conditional failure         |

```csharp theme={null}
var result = GetUser(id)
    .Then(user => GetOrders(user.Id))
    .Then(orders => orders.Where(o => o.Status == "Active"))
    .Else(errors => Array.Empty<Order>());
```

### Or Extensions

Convert nullable values to `ErrorOr<T>`:

```csharp theme={null}
// Returns Error.NotFound if null
User? user = FindUser(id);
ErrorOr<User> result = user.OrNotFound("User.NotFound", "User not found");

// Other extensions
value.OrValidation("Field.Invalid", "Invalid field");
value.OrUnauthorized("Auth.Failed", "Authentication failed");
value.OrForbidden("Access.Denied", "Access denied");
value.OrConflict("Resource.Exists", "Resource already exists");
value.OrFailure("Operation.Failed", "Operation failed");
value.OrError(customError);
```

## Success Sentinels

For endpoints that don't return a value:

```csharp theme={null}
[Post("/todos")]
public static ErrorOr<Created> Create(CreateTodoRequest req)
{
    _db.Add(new Todo(req.Title));
    return Result.Created;
}

[Delete("/todos/{id}")]
public static ErrorOr<Deleted> Delete(Guid id)
{
    _db.Remove(id);
    return Result.Deleted;
}

[Put("/todos/{id}")]
public static ErrorOr<Updated> Update(Guid id, UpdateTodoRequest req)
{
    _db.Update(id, req);
    return Result.Updated;
}
```

| Sentinel         | HTTP Status | TypedResult |
| ---------------- | ----------- | ----------- |
| `Result.Success` | 200         | `Ok`        |
| `Result.Created` | 201         | `Created`   |
| `Result.Updated` | 200         | `Ok`        |
| `Result.Deleted` | 204         | `NoContent` |
