An error type is for any deviation from the happy path that can be reasonably expected to occur during normal operation, and which my program must be able to handle. For a HTTP request, this would be something like "connection reset by peer" or "expected 200, got 404".
An exception is for any deviation from the happy path that a reasonable program cannot be expected to handle. For a HTTP request, this would be something like "malloc for send buffer failed".
Error types should be very visible in your function signature and their handling should be enforced or at least linted by the tooling, since failure to handle them very likely is a bug.
Exceptions, on the other hand, should be mostly invisible since most code cannot do anything when an exception occurs. In fact, if I had to design a language, I'd probably try to get by with reducing the try-catch-finally triad to try-finally or even just finally. Sometimes it's really useful to clean up after yourself before continuing to die, but if you can recover from an exception, you probably should have had an error value in the first place.