You can still, at the very least, `catch(Exception e)` or `catch(...)` to handle a failure. Odds are very good in my experience that you will anyway have nothing better to do than log the error and abort the higher-level operation (e.g. HTTP request handler), even if you do know the specific type of exception that happened.
Also, even in languages that have error return types/codes, it's very uncommon to see anything other than the most generic error value/return code allowed by the convention (e.g. `return -1` in C or `return fmt.Errorf("...")` in Go). Writing an API to document all possible failure modes is hard, and is rarely done, regardless of the mechanics of how errors are returned.
One of the exceptions I've often seen is in SQL APIs, which generally do need to report the specific SQL errors that were signaled. And here, I've seen all possible errors explicitly exposed in the API, typically through a rich Error or Exception type that has a field for the specific SQL error code.
Not to mention, we were mostly discussing cases where a library finds itself in a bug situation, say a null pointer case. I would not expect the API to express the possibility of "NullPointerException" or "ArrayIndexOutOfBounds" as possible return values, but I do want the language to raise these and allow me to decide how to handle them instead of simply halting the entire program - at least in managed memory languages where memory corruption is not possible/likely (if there is a good chance of memory corruption, like in C++, halting is indeed much better than raising an exception).