How you handle failures deeply affects the readability and maintainability of your architectural layers.
In standard .NET, we throw exceptions (e.g., NotFoundException). In the Presentation layer, we use a **Global Exception Handler** to catch these and map them to HTTP 404/400. This is easy, but it makes the 'Failure Path' invisible in the method signature.
Instead of throwing, methods return a Result<T> object that contains either the Value or an Error. This makes the possibility of failure explicit. var result = await service.DoWork(); if (result.IsFailure) return BadRequest(result.Error);. This is common in functional programming and leads to code that is much easier to reason about and test.
Q: "Which one is better for Clean Architecture?"
Architect Answer: "Use the **Result Pattern** for business logic failures (e.g., 'Insufficient Funds'). This is a 'Domain' result. Use **Exceptions** only for truly unexpected technical failures (e.g., 'Database is Down'). This separation tells the reader exactly which errors are 'Business as usual' and which are 'Critical failures'."