First of please stop comparing everything to a goto statement - since exceptions lead controll flow only in one direction (forward) they have as much (or more) similarities to an if-else statement than a goto statement (the original and the wattered down version that exists in the popular languages).
Regarding exceptions they don't add anything that shouldn't already be expected (like a chip on the server's motherboard getting fryed or ups breaking and nobody noticing that until there is a power shortage - both happened at my workplace) - it only adds some additional gracefullness to it (or you can just terminate in the catch block) - so I don't buy the part where you say that there are no exceptional cases.
One other example is when we hit the ulimit on the server and an allocation failed - it was a corner case with reading a speciffic file that managed to pass the size check but exploded in size after parsing - the program crashed but since wh had 5 instances that were respawned if killed we just got lots of crashes on that file but only one angry client (the rest of files were processed as always). After adding a single catch block to an existing try we could log the issue, move the file and move to the next one without crashing. This added a bit faster recovery time but that was pretty much the only meaningful difference. Now imagine littering the entire code with if null allocation checks and moving that error through 5-7 layers of call stack (including xerces parser that expected an exception throw to terminate parsing prematurely) while still having only one place in code (the file fetching loop) where you could do anything meaningfull about it. I wouldn't want to see such code.
Exceptions shouldnt be used everywhere but there are cases and not all of my programs need/handle them so perhaps you just always work on programs that don't need them.
As for your questions:
Regarding learning of them I would prefer to have modules requirement that all expected exceptions that can escape outside a module must be annotated in the api (hard barriers to otherwise exception wise blissfull world) but that's not the case. But neither is there any difference with error codes. Sure you can check if-ok-then-this-else-tough-luck but in the end you still can't handle the unknown case (except logging). For serious fixing you need reproducable input and fammiliarity with the code. And in all honesty nhere are not allot of places where people pull out power or internet cables just to check the exceptions/error codes so you are always in the land of unknown so you should treat the unknown case.
If somebody adds an exception that you can't handle it's the unknown case anyway (and complain to the person that adds exceptions/new error codes liberaly all over the place without notifying you first).
If somebody removes an error code your error handling is dead code as well (usualy int is used or an enum that is returned from multiple functions so removing it in one function doesn't give you the right to remove the enum case thus making the removal silent).
As you noted exceptions are the "handle elsewhere far far away" mechanism and if you have reproducable inputs you don't even need to add logging between call and processing site (same goes if you know that you only open one file/instantiate a single instance of xyz parser).
Exceptions are not a cure for everything but neither are error codes in return statements. They both have their place and annoy the crap out of me when one is used in case where the other would be a better fit (so I'm glad that std::filesystem has both apis).
Hope some of this is useful for you.