{"record":{"id":"1592bec07a6704fb","repo":"nodejs/node","slug":"macro-r-takes-not-more-than-d-argument-s","errorCode":null,"errorMessage":"macro %r takes not more than %d argument(s)","messagePattern":"macro %r takes not more than (.+?) argument\\(s\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"tools/inspector_protocol/jinja2/runtime.py","lineNumber":572,"sourceCode":"            caller = kwargs.pop('caller', None)\n            if caller is None:\n                caller = self._environment.undefined('No caller defined',\n                                                     name='caller')\n            arguments.append(caller)\n\n        if self.catch_kwargs:\n            arguments.append(kwargs)\n        elif kwargs:\n            if 'caller' in kwargs:\n                raise TypeError('macro %r was invoked with two values for '\n                                'the special caller argument.  This is '\n                                'most likely a bug.' % self.name)\n            raise TypeError('macro %r takes no keyword argument %r' %\n                            (self.name, next(iter(kwargs))))\n        if self.catch_varargs:\n            arguments.append(args[self._argument_count:])\n        elif len(args) > self._argument_count:\n            raise TypeError('macro %r takes not more than %d argument(s)' %\n                            (self.name, len(self.arguments)))\n\n        return self._invoke(arguments, autoescape)\n\n    def _invoke(self, arguments, autoescape):\n        \"\"\"This method is being swapped out by the async implementation.\"\"\"\n        rv = self._func(*arguments)\n        if autoescape:\n            rv = Markup(rv)\n        return rv\n\n    def __repr__(self):\n        return '<%s %s>' % (\n            self.__class__.__name__,\n            self.name is None and 'anonymous' or repr(self.name)\n        )\n\n","sourceCodeStart":554,"sourceCodeEnd":590,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/inspector_protocol/jinja2/runtime.py#L554-L590","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n{% macro greet(name) %}Hi {{ name }}{% endmacro %}\n{{ greet('Ann', 'Bob') }}\n// after\n{% macro greet(*names) %}Hi {{ names|join(', ') }}{% endmacro %}\n{{ greet('Ann', 'Bob') }}","handlingStrategy":"validation","validationCode":"import re, pathlib\nmacro_re = re.compile(r'\\{%\\s*macro\\s+(\\w+)\\(([^)]*)\\)\\s*%\\')\nfor p in pathlib.Path('templates').rglob('*.html'):\n    src = p.read_text()\n    defs = {m.group(1): m.group(2) for m in macro_re.finditer(src)}\n    # check call sites that spread *items\n    for call in re.finditer(r'(\\w+)\\(\\*([\\w.]+)\\)', src):\n        name = call.group(1)\n        if name in defs and '*' not in defs[name]:\n            arity = len([a for a in defs[name].split(',') if a.strip()])\n            print(f'{p}: {name}(*{call.group(2)}) - macro takes {arity} positional')","typeGuard":"def arity_ok(positional_count: int, macro_param_count: int, has_varargs: bool) -> bool:\n    return has_varargs or positional_count <= macro_param_count","tryCatchPattern":"# arity mismatch is a template bug; fix call site or macro signature","preventionTips":["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."],"tags":["jinja2","runtime","macro","arity","positional-args"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}