The difference is that callers (even indirect callers) can register handlers to handle those errors without unwinding the stack.
Maybe the error handler makes it return a default value. Maybe it will deallocate a cache to free up memory in a memory-constrained situation. Maybe it purely ignores EOF or a FILE DOES NOT EXIST error where those do not matter.
I also have a special error handler for parsing. If the error is a parse error, it prints the parse error in standard format, with source file, line, etc. Otherwise, it passes the error on to the next error handler in the chain.
This helps me modularize my code by keeping the parse error concerns separate from error handling for everything else.
It was perfect, except for all the crashes from null variables back then. And my current favourite language Dart cuts null pointers by 99.99 percent by giving you null safety.
Checked exceptions and null safety, and suddenly programs crash like 90 percent less.
Now we must just figure out how to systematically eliminate index-out-of-bounds too, then 98 percent of program crashes are gone. All without writing unit tests and other costly rituals.
Just good language design.