You've just described Scala which inspired many of Rust's features.
Swift I suppose although it doesn't make much sense outside of the Apple ecosystem.
For bubbling up errors you have the ? operator, then on results you have map, map_err, and, ok_and...
Sometimes you want to return a partial result along with an error. Go's idiom of returning multiple values, with the final value being an error, allows this situation to be easily supported.
And if you wanted to do that in rust, that's a valid thing too, either as using a tuple instead of a sum type, or a tuple in the Err side of a result. You can describe what you're trying to do simply with the function signature.
Sometimes you do, and there are types that represents that. Having a single type that is almost always used a certain way but occasionally used subtly differently is a trap waiting to bite you.
Go has a convention of documenting each function with a comment (which is adhered to by the standard library, my own code, and any other code I'd consider worthy of depending on).
So when I think this subtlety matters, I check the documentation. Usually I don't care either way: When I get a non-nil error, I typically don't care about the other result (whether partial or the zero value).
The distinction rarely matters in practice (and when it does, the documentation is there). I think this simplicity is the right tradeoff (vs. being burdened with more types to think about).
So it's not that a type is more of a burden than documentation, but rather that a type is an additional burden (since we're taking on the documentation burden either way).
I like that Go's error handling is simple enough that I can keep all its rules in my head. And I like that the other parts of Go are simple like that too. It allows me to easily know exactly what is going on at the language level (while my attention is focused on higher levels).
If I get a result that came with a non-nil error, and I still plan to do something with the result, then it seems natural to think about the possibility that the result might be nil. I would consult the function's documentation, and maybe its source, and then maybe put in a nil check.
This is too rare a problem to be worth adding complexity to the language. There needs to be a big payoff for adding complexity. A language gets hard to use if it adds micro-complexities all over the place for the sake of preventing rare programming mistakes.
Rust is actually largely error-unaware. It does have some syntactic sugar (mostly `?`, and even then that’s not restricted to errors), but for the most part Result just an enum with a `must_use` annotation, everything flows down from that.
There _is_ some futzing that sometimes have to happen due to various operations' Result types using incompatible Error types. That's just a thing that has to be dealt with.
It's also often taken care of by a sort thiserror macro invocation per "inner" type. There are obviously more complex error setups, but this covers the vast majority IME
I get why this is, but it does make me miss the Python Exception model of "there's ~15 base exception types. One of them is probably good enough for you". One could point out that the arguments are usually "just" strings there too, but at least there's some conventions.
I understand Rust's philosophy, I just find it annoying.
Being able to define your own app-specific Error type which everything gets converted to is incredibly useful and powerful. Especially for web apps where you can return the correct response codes depending on the error.