Skip to content

ZibStack.NET.Result — Alternatives

The “Result pattern” for functional error handling in .NET has four well-known libraries, each with a different philosophy:

  • FluentResults — one result type, error collection, metadata-heavy
  • OneOf — true generic discriminated unions (OneOf<T1, T2, T3>), maximum type precision
  • ErrorOr — middle ground, ErrorOr<TValue> with typed Error records
  • LanguageExt — full functional-programming stack (Option, Try, Either, …) — powerful but a lot to learn

ZibStack.NET.Result sits in the same space, opinionated toward pragmatic server-side APIs: one Result<T> / Result<T, TError> with typed errors, Railway-oriented composition (Then / Map / Bind), and ergonomic converters to ASP.NET Core ProblemDetails / HTTP responses.

FeatureZibStack.NET.ResultFluentResultsOneOfErrorOrLanguageExt
Philosophypragmatic Result + Error, HTTP-friendlyone result + collection of errorstrue discriminated unionstyped Error records + resultfull FP stack (Option/Try/Either)
Learning curvelowlowlow–mediumlowhigh (FP background needed)
Multiple outcome branchesResult<T, TError> typed error channelsingle error bag✅ via OneOf<T1, T2, T3>single error✅ via Either
ASP.NET Core ProblemDetails helpers✅ native ToProblemDetails() / ToHttpResult()community
Railway ops (Map / Bind / Then)partial (via switch)✅ deep
Pattern matching on outcome.Match(val, err).IsSuccess / .ErrorsMatch(a => …, b => …).Match(val, err)
Error metadata / hierarchytyped Error with Type/Code/Description + metadata✅ rich IError objectsvia TErrortyped Error with categoryvia Error type
Implicit conversions (return value; / return error;)partialpartial
Runtime coststruct-based where possiblealloc per resultunion-sized struct possiblestructvariable
Install footprintsmallsmallsmallsmalllarge

Not a full functional-programming stack. If you want Option<T> instead of T?, Try<T> for exception wrapping, IEnumerable as Seq<T> with FP methods, persistent collections, etc. — that’s LanguageExt’s turf and this package doesn’t compete there.

Not a true N-way discriminated union. Result<T, TError> is two branches; if you need three (e.g. NotFound | Forbidden | Ok<T> as distinct types), OneOf models that more precisely.

Server-side APIs where every handler returns either a success payload or a typed error that needs to flow cleanly to an HTTP response. Built-in ProblemDetails conversion, [CrudApi] endpoints wired to return Result<T> → HTTP status codes automatically. One dependency, no FP ramp-up, works with ASP.NET Core / Minimal API / Controllers without ceremony.

  • OneOf — you genuinely have >2 distinct outcome types and want the compiler to enforce exhaustive matching across all of them.
  • LanguageExt — your team is comfortable with FP idioms and you want the whole toolbox (Option/Try/Either/Validation/State/…).
  • ErrorOr — you specifically prefer its Error record API and the implicit conversion patterns in its ecosystem.
  • FluentResults — you need rich error hierarchies with multiple errors per result, metadata on each, and aren’t focused on HTTP mapping.