nodejs/node · error · TypeError
macro %r takes not more than %d argument(s)
Error message
macro %r takes not more than %d argument(s)
What it means
Raised by Macro._invoke when the macro does not accept catch_varargs (no *args) and the number of positional arguments supplied exceeds self._argument_count (the number of declared positional parameters). The runtime reports how many arguments the macro actually takes.
Source
Thrown at tools/inspector_protocol/jinja2/runtime.py:572
caller = kwargs.pop('caller', None)
if caller is None:
caller = self._environment.undefined('No caller defined',
name='caller')
arguments.append(caller)
if self.catch_kwargs:
arguments.append(kwargs)
elif kwargs:
if 'caller' in kwargs:
raise TypeError('macro %r was invoked with two values for '
'the special caller argument. This is '
'most likely a bug.' % self.name)
raise TypeError('macro %r takes no keyword argument %r' %
(self.name, next(iter(kwargs))))
if self.catch_varargs:
arguments.append(args[self._argument_count:])
elif len(args) > self._argument_count:
raise TypeError('macro %r takes not more than %d argument(s)' %
(self.name, len(self.arguments)))
return self._invoke(arguments, autoescape)
def _invoke(self, arguments, autoescape):
"""This method is being swapped out by the async implementation."""
rv = self._func(*arguments)
if autoescape:
rv = Markup(rv)
return rv
def __repr__(self):
return '<%s %s>' % (
self.__class__.__name__,
self.name is None and 'anonymous' or repr(self.name)
)
View on GitHub (pinned to 1b2de5e052)
Solutions
- Trim the call to the declared arity, or add parameters/defaults to the macro.
- Add catch_varargs: {% macro my_macro(a, *rest) %} if variadic calls are intentional.
- Validate the input list length in Python before render: assert len(items) <= expected.
- Lock the shared-macro version with a pin and add a regression test for arity.
Example fix
// before
{% macro greet(name) %}Hi {{ name }}{% endmacro %}
{{ greet('Ann', 'Bob') }}
// after
{% macro greet(*names) %}Hi {{ names|join(', ') }}{% endmacro %}
{{ greet('Ann', 'Bob') }} Defensive patterns
Strategy: validation
Validate before calling
import re, pathlib
macro_re = re.compile(r'\{%\s*macro\s+(\w+)\(([^)]*)\)\s*%\')
for p in pathlib.Path('templates').rglob('*.html'):
src = p.read_text()
defs = {m.group(1): m.group(2) for m in macro_re.finditer(src)}
# check call sites that spread *items
for call in re.finditer(r'(\w+)\(\*([\w.]+)\)', src):
name = call.group(1)
if name in defs and '*' not in defs[name]:
arity = len([a for a in defs[name].split(',') if a.strip()])
print(f'{p}: {name}(*{call.group(2)}) - macro takes {arity} positional') Type guard
def arity_ok(positional_count: int, macro_param_count: int, has_varargs: bool) -> bool:
return has_varargs or positional_count <= macro_param_count Try / catch
# arity mismatch is a template bug; fix call site or macro signature
Prevention
- Add *args to macros intended to receive variadic input.
- Bound data-driven spreads in Python before render: items = items[:max_arity].
- Lock shared macro versions and add arity regression tests.
When it happens
Trigger: Calling {{ my_macro(1, 2, 3) }} when my_macro is {% macro my_macro(a) %}. Passing a list as positional args via the * form: {{ my_macro(*items) }} where len(items) exceeds the parameter count. Macro refactored to take fewer parameters but call sites unchanged.
Common situations: Removing a macro parameter without updating call sites. Data-driven rendering where the input arity varies but the macro is fixed. Templating helpers imported from a shared library whose signature changed across versions.
Related errors
- macro %r was invoked with two values for the special caller
- macro %r takes no keyword argument %r
- no items for cycling given
- Tried to call non recursive loop. Maybe you forgot the 'rec
- at least one item has to be provided
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/1592bec07a6704fb.
Report an issue: GitHub.