Skip to content

Named macro arguments incorrectly resolved when optional parameter is skipped out of declaration order #707

@gdulik

Description

@gdulik

Describe the bug

When calling a macro with named arguments and skipping an optional parameter, Askama incorrectly resolves subsequent arguments if they are passed out of declaration order. The parser appears to fall back to positional mapping after encountering the first out-of-order argument, causing the compile error.

Misleading error message:
The compiler error claims the argument is passed more than once, which is incorrect and obscures the real cause:

error: `val1` is passed more than once
         --> templates/hello.html:3:13
       "(val3=\"\", val1=\"\") }}"
 --> src/main.rs:4:19
  |
4 | #[template(path = "hello.html")]
  |                   ^^^^^^^^^^^^

To Reproduce

Minimal reproduction repo is available here

Define a macro with one required and two optional parameters:

{% macro bug(val1, val2="", val3="") %}
  ...
{% endmacro %}

Call it skipping val2 and passing val3 before val1:

{% import "macros.html" as macros %}

{{ macros::bug(val3="c", val1="a") }}

Expected behavior:
Arguments are resolved by name regardless of order. val1="a", val2="" (default), val3="c".
Actual behavior:
Compile error or incorrect argument assignment — the parser misidentifies which value belongs to which parameter.
Workaround:
Always pass arguments in the exact order they are declared in the macro signature, even when using named argument syntax:

{{ macros::bug(val1="a", val3="c") }}

Additional findings:
The bug only reproduces when the macro is called from an imported file. Calling the macro directly within the same file as its definition works correctly.

{# works fine — same file as definition #}
{% macro bug(val1, val2="", val3="") %}{{ val1 }}{% endmacro %}
{{ self::bug(val3="c", val1="a") }}
{# breaks — macro imported from another file #}
{% import "macros.html" as macros %}
{{ macros::bug(val3="c", val1="a") }}

This suggests the bug is in the import resolution / cross-file argument matching logic rather than the macro parser itself.

Askama version
0.15.4

Rust version
1.93.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions