Attach context to all propagated errors with anyhow

When I use anyhow::Result, I know I can "attach context" to a particular Result. As I understand it, this essentially wraps the error with my custom error description.

use anyhow::Result;
fn read_some_data() -> Result<String> {
  let mut f = File::open("...").context("Something happened opening the file");
}

If I print this error with {:#} I would get for example:

Something happened opening the file: File not found

How would I go about attaching context to any error that is propagated from my function?

Essentially I would like to write:

use anyhow::Result;
fn read_some_data() -> Result<String> {
  let mut f = File::open("...")?;
  let mut b = String::new();
  f.read_to_string(&mut b)?;
}

and when I print the error, I would like to get:

Something happened in the read_some_data function: File not found

What code do I have to add?

You can wrap the code in an inner function or closure:

fn read_some_data() -> Result<String> {
    fn inner() -> Result<String> {
        let mut f = File::open("...")?;
        let mut b = String::new();
        f.read_to_string(&mut b)?;
        Ok(b)
    }
    inner().context("Something happened in the read_some_data function")
}

In the future, try blocks will offer a more concise way to do this.

Update: The context-attribute crate offers another solution.

1 Like

I'm using nightly, so I should already be able to enable them somehow?

Yes, using a feature attribute at the top level of your crate. For example:

#![feature(try_blocks)]

use std::{io::Read, fs::File};
use anyhow::{Context, Result};

pub fn read_some_data() -> Result<String> {
    let r: Result<String> = try {
        let mut f = File::open("...")?;
        let mut b = String::new();
        f.read_to_string(&mut b)?;
        b
    };
    r.context("Something happened in the read_some_data function")
}
3 Likes

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.