Basically. It's a little different because you have more control. It's way too easy to assume exceptions won't happen and basically ignore them. But they happen in unexpected places (e.g. every time when dealing with IO).
Exceptions only contain a function call trace (stack of function calls), while a logical error trace is more like an explicit try/catch/wrap/throw around every call and could be more informative to the end user if done properly.
This does not require exceptions. A very simple implementation could involve appending the additional error to the messsage from the lower error level. As far as I understand, exceptions were invented so that error handling code will not clutter up the "happy path". They allow "exceptional condition handling" to be seggregated. But in real world applications you may need to, say, recover from an error. For example, if connection using https fails, fallback to http. This makes code using exceptions look wonky. So might as well use error codes always
>instead of always blindly returning an error, one could wrap them in higher level errors and build a sort of error trace
Isn't that basically just reinventing exceptions, sort-of ?