Error Handling¶
Every generated effect method wraps errors with contextual information automatically. When an effect fails, the error tells you which service and which method failed — not just the raw exception.
Auto-Inferred Error Context¶
The generator infers an error prefix from the interface name by stripping the I prefix:
| Interface | Inferred Prefix |
|---|---|
IPaymentGateway |
PaymentGateway |
IEmailService |
EmailService |
IInventoryService |
InventoryService |
Every generated effect method gets .MapFail() wrapping:
// Generated:
liftEff<RT, Receipt>(async rt => await rt.PaymentGateway.ChargeAsync(amount, currency))
.MapFail(e => Error.New("PaymentGateway.ChargeAsync failed", e))
.WithActivity("PaymentGateway.ChargeAsync", ActivitySource);
No code changes needed — declare the module and error context is automatic:
Error Chain in Practice¶
When a workflow composes multiple services and one fails, the error chain tells you exactly where:
public static Eff<AppRuntime, OrderId> Handle(CreateOrder cmd) =>
from order in OrderEffects.Orders.CreateAsync<AppRuntime>(cmd.ToOrder())
from _charge in PaymentEffects.PaymentGateway.ChargeAsync<AppRuntime>(cmd.Total, "USD")
from _notify in NotifyEffects.Notifier.SendAsync<AppRuntime>(order.Id, "created")
select order.Id;
If the payment gateway fails:
If the notification service fails instead:
Each error in the chain carries the service and method name, making debugging straightforward — especially in production logs and OpenTelemetry traces.
Overriding the Prefix¶
The inferred name works for most interfaces. When it doesn't, use ErrorPrefix:
[EffectsModule(typeof(IPaymentGateway), ErrorPrefix = "Payments")]
public sealed partial class PaymentEffects;
// → "Payments.ChargeAsync failed"
[EffectsModule(typeof(IExternalApiV2Client), ErrorPrefix = "ExternalApi")]
public sealed partial class ExternalApiEffects;
// → "ExternalApi.FetchAsync failed"
Composing with Manual .MapFail()¶
The auto-inferred context provides service-level identification. For domain-level context, compose .MapFail() at the call site:
from _ in PaymentEffects.PaymentGateway.ChargeAsync<AppRuntime>(cmd.Total, "USD")
.MapFail(e => Error.New($"Payment failed for order {orderId}", e))
This produces a three-level error chain:
Error: Payment failed for order ORD-123
→ Error: PaymentGateway.ChargeAsync failed
→ HttpRequestException: Connection refused
The auto-inferred prefix and manual .MapFail() compose naturally — use both when you need domain context on top of service context.
How Errors Map to HTTP Responses¶
WebError.ToResult() maps effect errors to appropriate HTTP status codes. Error context is preserved in the response:
| Error Type | HTTP Status | Body |
|---|---|---|
ValidationError |
422 | Structured {field, code, message} array |
Expected |
Status from Expected.Code |
Error message |
Any other Error |
500 | Error chain as message |
See Dispatch Validation for the validation-specific error story.