How to deal with multiple error types?

I'm new to Rust. Coming from a C/C++/Go background, one thing I'm having trouble is dealing with functions that may return different error types.

For example,


enum CustomError {
   InvalidConfig
}

fn read_config<P: AsRef<Path>>(path: P) -> Result<Config, ??> {
      let contents = fs::read_to_string(path)?; // may return std::io::Error
      let cfg: Config = serde_json::from_str(&content)?; // may return serde_json::Error
      cfg.validate()?; // may return CustomError
      Ok(cfg)
}

How does one deal with multiple Error types? I could return Result<Config, Box<dyn std::error::Error>>, but I'm wondering if there's an idiomatic way to solve this.

One straighforward way is to define your own enum Error which provides From implementations for all kinds of errors you expect to encounter. Crates such as thiserror can help reduce the corresponding boilerplate.

This is idiomatic as well depending on your use-case and laziness.

The way I have approached this is to create wrappers for functions which return an incompatible Result type and repackages them into a compatible type. For example:

#[derive(PartialEq,Debug,...)]  // make it easier to print in an eprintln!() macro, to check for in tests, etc.
enum CustomError {
    InvalidConfig,
    PathConversionError(std::io::Error),
    JsonValidationError(...);  // too lazy to look up member type here, but you get the idea I think.
    JsonConversionError(...);
}

fn convert_path_to_string<P: AsRef<Path>>(path: P) -> Result<String, CustomError> {
    match fs::read_to_string(path) {
        Ok(s) => Ok(s),
        Err(e) => Err(CustomError::PathConversionError(e)),
    }
}

fn string_to_config(content: &str) -> Result<Config, CustomError> {
    match serde_json::from_str(content) {
        Ok(json) => match json.validate() {
            Ok(cfg) => Ok(cfg),
            Err(e) => Err(CustomError::JsonValidationError(e)),
        },
        Err(e) => Err(CustomError::JsonConversionError(e)),
    }
}

pub fn read_config<P: AsRef<Path>>(path: P) -> Result<Config, CustomError> {
      let contents = path_to_string(path)?;
      let cfg: Config = string_to_json(contents)?;
      Ok(cfg)
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.