If you're using a language with exception-handling and automated resource management, your colleagues should probably get used to your preferred style with premature exits in the case of encountering a external input error.
The idea of trying to shift function exits towards the bottom of the scope was useful in the days before exception handling and automated resource management (ex: languages without destructors or GC like C) because error recovery often required manual cleanup.
In those manual cleanup cases, it was often useful to shift the exits towards the bottom of a function so that you could look at the top of the function for the logic creating the temporary resources needed by the function and towards the bottom of the function to see the symmetrical clean up of those resources.
In such cases as with assembly, it's quite common to see jumps/branches
to an error label at the bottom of the function where the clean up would occur. It's also not too uncommon even in C using gotos
for this purpose.
Also, as mentioned, deep nesting introduces a lot of mental overhead. Your brain has to function like a deeply-nested stack trying to remember where you're at, and as even Linus Torvalds, a diehard C coder, likes to say: if you need something like 4 nested levels of indentation in a single function, your code is already broken and should be refactored (I'm not sure I agree with him about the precise number, but he has a point in terms of how it obfuscates logic).
When you move into a more modern language like C++, you now have automated resource management via destructors. Functions should then no longer be mentioning cleanup details, as the resources should handle the cleanup automatically by conforming to what's called the resource acquisition is initialization idiom (not exactly the best name). That eliminates one of the big reasons to favor a style that strives to have error handling logic towards the bottom.
On top of that, when you use a language like C++, it potentially throws exceptions and all over the place. So it's not uncommon for every other line of code to have the effect of having a hidden, implicit exit with logic like this:
if an exception occurs:
automatically cleanup resources and propagate the error
So there are hidden, premature exits all over the place. So if you use a language like that, not only should you get used to premature exits in the case of an exception, but you're kind of forced into it and have no other choice. As far as readability/traceability is concerned in those languages, you can't get any simpler than:
if something bad happened:
return error
The one exception I'd suggest to the rule is static branch prediction. If you're writing very performance-critical code where the smallest of micro-efficiencies counts more than readability, then you want your branches to be weighted towards favoring the common case line of execution as Intel advises. So instead of:
if something exceptional happened:
return error
... for performance you might invert the logic and do this instead:
if something normal happened:
...
return success
return error