In a classic application development, where the caller of your method runs in the same process as your logic, it's obvious that when an error occurs, the code will either throw an exception or return an error code of some type.
In a Web API application, we strive to get the same semantic, only that the caller doesn't run in the same process, and therefore, the error response should be serialized on the wire. HTTP already provides the notion of status code, which allows you to communicate to the caller if the request was processed successfully or not. Unfortunately, in many cases, this is not enough, and the users of your API are unable to understand exactly what the problem is by only looking at a single generic status code. Instead, it's better to provide a standard error object with finer details...