Serde / TOML error reporting

tldr: Any way to get Serde/TOML to produce decent error output?

Error reporting in Rust is really wonderful.

Unfortunately I can't currently say the same about Serde for toml files. If there's an error, I get a one-line result, containing the error message and a dump of the toml content. No line breaks, and no line numbers. For example, making a typo of 'pxroperty_id' instead of 'property_id' gives

Error: Error { inner: Error { inner: TomlError { message: "missing field property_id", original: Some("[configuration]\npxroperty_id=... (half a screen containing a debug dump of the entire TOML file).

I'm thinking that this is an issue with the TOML deserialize implementation, not Serde itself (since I tried it with JSON and the result is reasonable). Seems a bit ironic, since it seems as if JSON is more likely to be machine generated whereas TOML is likely to be hand entered (specifically to avoid using JSON with its limitations for configuration).

I am thinking that this is either inherent to Serde/TOML, or I'm missing a configuration setting. I'm using the declarative variant, but don't have any particular settings for Serde.

It's a personal project, so I will live with it if the solution is to write a pile of custom code (which smells to me like rewriting the TOML driver). However, if this was 'themware' or 'usware' it would need to be addressed.

You're using the debug-formatting of the error type, which is not meant to look pretty. Maybe the error type has a method to get a nicely formatted output or try construction your own out of the line number and message text.

1 Like

That seems to be the trick, thanks!

Details of the solution...

 fn load_specification_from_toml_file(filename: &str) -> Result<Specification, Box<dyn Error>> {
    let contents = fs::read_to_string(filename)?;
    // Nope, badly formatted:
    // let specification = toml::from_str(&contents)?;
    let specification = match toml::from_str(&contents) {
        Ok(s) => s,
        Err(e) => {
	        let s = e.to_string();
	        eprintln!("{}", s);
	        return Err("Error loading specification".into());
        }
    };
    Ok(specification)
 }

 fn main() -> Result<(), Box<dyn Error>> {
    // elided...
    let specification = load_specification_from_toml_file(&arguments.report_configuration)?;
    // elided...
    Ok(())
 }

So the original working of this had the code at 'Nope, badly formatted'. This passes the error back to main, which in turn passes it back to the runtime support, which prints it (in the debug format, as noted by jendrikw).

The new working displays the error explicitly, then passes back a generic error message. That formats properly, and gives a useful-to-the-user message.

The thing that was leading me astray is that doing the same thing with the json library:

fn load_data_from_json_file(filename: &str) -> Result<Data, Box<dyn Error>> {
    let contents = fs::read_to_string(filename)?;
    let data = serde_json::from_str(&contents)?;
    Ok(data)
}

works fine (or at least, well enough to be user-useful). I guess that internally the json code is setting up a different sort of error response.