rusttera

tera: Display line number and type of the failure for rendering errors


I have the following code in Rust using tera template language:

    let mut context = Context::new();
    context.insert("adminform", &admin_form);
    let html = match tera.render("change_form.html", &context) {
        Ok(html) => html,
        Err(err) => return HttpResponse::InternalServerError().body(format!("Failed to render the template: {}", err))
    };

The rendering fails, but the only information I receive is:

Failed to render the template: Failed to render 'change_form.html'

How can I get a more detailed error? I need to get the line number and exact failure to debug and fix.


Solution

  • It seems the error contains more information in its source, making this a chained error.

    By default, println!("{}") only prints the last error of the chain. Printing with {:?} (debug-printing) would reveal more information.

    There are frameworks that can visually display the entire chain, like miette. Be aware that you need to enable the fancy feature of miette for this to work.

    // Define some errors which can create an error chain
    mod errors {
        use thiserror::Error;
    
        #[derive(Error, Debug)]
        #[error("MyErrorA: {msg}")]
        pub struct MyErrorA {
            pub msg: String,
            #[source]
            pub source: MyErrorB,
        }
    
        #[derive(Error, Debug)]
        #[error("MyErrorB: {msg}")]
        pub struct MyErrorB {
            pub msg: String,
        }
    }
    
    use miette::IntoDiagnostic;
    
    fn main() {
        let err = Err(errors::MyErrorA {
            msg: "Outer error!".to_string(),
            source: errors::MyErrorB {
                msg: "Source error!".to_string(),
            },
        });
    
        match err.into_diagnostic() {
            Ok(()) => println!("Success!"),
            Err(e) => {
                let pretty_error = format!("{:?}", e);
                // Do something with the pretty error, like inserting it in a HTML message.
                // In this case, I'll print it.
                println!("{}", pretty_error);
            }
        }
    }
    
      × MyErrorA: Outer error!
      ╰─▶ MyErrorB: Source error!
    

    So in your case, I might guess that something like the following might work. I can't be sure, though, because your example isn't reproducible for me to test it. So be aware that the following code is untested.

        let html = match tera.render("change_form.html", &context).into_diagnostic() {
            Ok(html) => html,
            Err(err) => return HttpResponse::InternalServerError().body(format!("Failed to render the template: {:?}", err))
        };