Returns go straight up the stack only if you choose them to. Caller doesn't have to propagate errors and return immediately, it can hold onto them and/or process them in the natural place they occur, they are just values. The returns from your function can be found with "grep return".
Exceptions, by default, break the natural control flow unless you wrap everything with try/catch. Even then, a lot of constructs won't be very natural and you really will have to get out of your way to identify the source of the exception, which very frequently is more important than it's type.
(Panics of course can cause similar thing in Go but that's the reason why they should rarely be recovered and not used as a value propagation mechanism.)
func thing(arg) {
otherThing(arg) // does this return an error you're ignoring?
}
It even has a similar problem, where void returns -> err returns on code changes are not visibly discoverable (similar to a newly-throwing func).Granted, you could turn this into a compiler error. But it's not currently.
---
Anyway. Given that so many not-prevented-by-the-typesystem operations panic, I don't think it's reasonable to assume that any func call will not panic, especially not in the future since they may change. So you already have to program with `defer` to maintain your invariants, which is exactly the same as with exceptions, except you now have to deal with both possibilities for nearly every func.