If it internally has a `InnerFuncErr::WriteFailed` error, you might handle it, and then you don't have to pass it back at all, or you might wrap it in an `OuterFuncErr::BadIo(inner_err)`or throw it away and make `BadIo` parameterless, if you feel that the caller won't care anyways.
Errors are not Exceptions, you don't fling them across half of your codebase until they crash the process, you try to diligently handle them, and do what makes sense.
So you don't really care about the union.
Your function typically has a specific intent when it tries to call another function. Say that you have a poorly designed function that reads from a file, parses the data, opens a DB connection and stores the data.
Should I really expect an end-user to understand an error generated by diesel/postgres/wtfdb? No, most likely I want to instruct them to generate debug logs and report an issue/contact support. This is most likely the best user experience for an application. In this case, each "action" of the function would "hide" the underlying error––it might provide information about what failed (file not found, DB rejected credentials, what part of the file couldn't be parsed, etc), but the user doesn't care (and shouldn't!) about Rust type of diesel error was generated.
To answer your question specifically, I might go without something like this:
#[derive(Debug, Error, Clone)]
pub enum MyFunctionError {
#[error("unable to read data from file: {0}")]
ReadData(String),
#[error("failed to parse data: {0}")]
Parse(String),
#[error("database refused our connection: {0} (host: {1}, username: {2})")]
DatabaseConnection(String, String, String),
#[error("failed to write rows: {0}")]
WriteData(String),
}
Obviously this is a contrived example. I wouldn't use `#[from]` and just use `.map_err` to give internal meaning to error provenances. `DatabaseConnection` and `WriteData` might have come from the same underlying WTFDbError, but I can give it more meaning by annotating it.When building a library, however, yes, I most likely do want to use `#[from] io::Error` syntax and let the calling library figure out what to do (which might very well giving the user a userful error message and dumping an error log).