> when you cannot handle the error in the current code block and the function interface does not support returning enough information to the caller to detail what went wrong
Exceptions are, fundamentally, an alternate way to return from a function. That's why the general practice is to avoid using them for control flow - there's enough in the language already to support what you want to do, we don't need to instrument the entire stack when I could return a negative value to indicate the error.
The engineering problem to solve is deciding when to turn a void return into a boolean or enum. Just because there is space in the interface for an error code, doesn't mean it's the right choice. But likewise, just because exceptions are available, doesn't mean every error should be thrown.