Great reply and it mirrors some of my reflections.
For Rust errors, I consider defining a single error enum for the crate or module to be an anti-pattern, even if it's common. The reason is because of what you described: the variants no longer match what can actually fail for specific functions. There's work on pattern types to support subsets of enums, but until then I found that the best is to have dedicated errors per pub function.
I also feel that there's an ecosystem issue in Rust where despite "error as values" being a popular saying, they are still treated as second class citizens. Often, libs don't derive Eq, Clone or Serialize on them. This makes it very tedious to reliably test error handling or write distributed programs with strong error handling.
For Java, my experience with Exceptions is that they don't compose very well at the type level (function signatures). I guess that it's part of why they're used more for coarse handling and tend to be stringy.
For Rust errors, I consider defining a single error enum for the crate or module to be an anti-pattern, even if it's common. The reason is because of what you described: the variants no longer match what can actually fail for specific functions. There's work on pattern types to support subsets of enums, but until then I found that the best is to have dedicated errors per pub function.
I also feel that there's an ecosystem issue in Rust where despite "error as values" being a popular saying, they are still treated as second class citizens. Often, libs don't derive Eq, Clone or Serialize on them. This makes it very tedious to reliably test error handling or write distributed programs with strong error handling.
For Java, my experience with Exceptions is that they don't compose very well at the type level (function signatures). I guess that it's part of why they're used more for coarse handling and tend to be stringy.