handlebars-rust icon indicating copy to clipboard operation
handlebars-rust copied to clipboard

ParamTypeMismatchForName in 6.3.2

Open ehuss opened this issue 7 months ago • 1 comments

When updating to 6.3.2, we are having an issue with the following error:

RenderError { template_name: Some("an-included-file"), line_no: Some(3), column_no: Some(5), reason: ParamTypeMismatchForName("lower", "s", "str"), unimplemented: false }

The following is a partially minimized example that illustrates this:

# Cargo.toml
[package]
name = "foo"
edition = "2024"

[dependencies]
handlebars = { version = "6.3.1", features = ["dir_source"] }
serde_json = "1.0.140"
// src/main.rs
use handlebars::{
    handlebars_helper, Context, Decorator, DirectorySourceOptions, Handlebars, RenderContext,
    RenderError,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut handlebars = Handlebars::new();
    handlebars.register_decorator("set", Box::new(set_decorator));
    handlebars.register_helper("lower", Box::new(lower));

    let mut options = DirectorySourceOptions::default();
    options.tpl_extension = ".md".to_string();
    let includes = std::env::current_dir().unwrap();
    handlebars.register_templates_directory(includes, options)?;
    let data = serde_json::json!({});
    assert_eq!(
        handlebars
            .render_template(
                r#"
{{~*set somevalue="Example"}}
{{> an-included-file }}
"#,
                &data
            )
            .unwrap(),
        "This file is included.\n\nSee example\n"
    );

    Ok(())
}

handlebars_helper!(lower: |s: str| s.to_lowercase());

/// `{{*set var=value}}` decorator.
///
/// This sets a variable to a value within the template context.
fn set_decorator(
    d: &Decorator<'_>,
    _: &Handlebars<'_>,
    _ctx: &Context,
    rc: &mut RenderContext<'_, '_>,
) -> Result<(), RenderError> {
    let data_to_set = d.hash();
    for (k, v) in data_to_set {
        set_in_context(rc, k, v.value().clone());
    }
    Ok(())
}

/// Sets a variable to a value within the context.
fn set_in_context(rc: &mut RenderContext<'_, '_>, key: &str, value: serde_json::Value) {
    let mut gctx = match rc.context() {
        Some(c) => (*c).clone(),
        None => Context::wraps(serde_json::Value::Object(serde_json::Map::new())).unwrap(),
    };
    if let serde_json::Value::Object(m) = gctx.data_mut() {
        m.insert(key.to_string(), value);
        rc.set_context(gctx);
    } else {
        panic!("expected object in context");
    }
}

And the following file called an-included-file.md:

This file is included.

See {{lower somevalue}}

Running this with 6.3.1 succeeds, but 6.3.2 fails.

A general outline of what this is doing:

  • A set helper used to set variables from within a template.
  • A lower helper which is used to lowercase a value.
  • A directory source to load includes from the current directory.
  • A root template that sets a variable using set, and then an include of a file that is intended to call lower on that value.

I'm not clear what is going on or what the error message means.

ehuss avatar May 18 '25 02:05 ehuss

This might be an error introduced in our refactoring on partials. Will check for the case.

sunng87 avatar Jun 06 '25 23:06 sunng87