{"record":{"id":"70c5d94fb3131880","repo":"nodejs/node","slug":"macro-r-takes-no-keyword-argument-r","errorCode":null,"errorMessage":"macro %r takes no keyword argument %r","messagePattern":"macro %r takes no keyword argument %r","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"tools/inspector_protocol/jinja2/runtime.py","lineNumber":567,"sourceCode":"\n        # it's important that the order of these arguments does not change\n        # if not also changed in the compiler's `function_scoping` method.\n        # the order is caller, keyword arguments, positional arguments!\n        if self.caller and not found_caller:\n            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>' % (","sourceCodeStart":549,"sourceCodeEnd":585,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/inspector_protocol/jinja2/runtime.py#L549-L585","documentation":"Raised by Macro._invoke when the macro was declared without catch_kwargs (no **kwargs in its signature) but the caller passed a keyword argument whose name is not a declared parameter. The runtime reports the first offending keyword. The 'caller' special case is handled by error 633; this path covers all other unexpected keyword arguments.","triggerScenarios":"Calling {{ my_macro(size=10) }} when my_macro was defined as {% macro my_macro(name) %}. Passing HTML attributes as kwargs to a macro that does not accept **kwargs. Copy-pasting a call site from a different macro signature. Variable kwargs spread via **payload where payload contains keys the macro does not accept.","commonSituations":"Macro signature changes without updating all call sites. Shared macros called from many templates where some pass options that no longer exist. Jinja2 macros used like function calls by developers expecting Python-style defaults/kwargs.","solutions":["Add the missing parameter to the macro definition, or add catch_kwargs: {% macro my_macro(name, **kwargs) %}.","Remove the unexpected keyword from the call site.","When spreading **payload, sanitize it first: {% set clean = payload|rejectattr_name_not_in_macro %} or filter in Python before render.","Add defaults in the signature so callers can omit: {% macro my_macro(name, size=10) %}."],"exampleFix":"// before\n{% macro button(label) %}<button>{{ label }}</button>{% endmacro %}\n{{ button('OK', cls='primary') }}\n// after\n{% macro button(label, cls='default') %}<button class=\"{{ cls }}\">{{ label }}</button>{% endmacro %}\n{{ button('OK', cls='primary') }}","handlingStrategy":"validation","validationCode":"import inspect, re, pathlib\n# parse macro definitions and their call sites; flag kwargs not in the signature\nmacro_re = re.compile(r'\\{%\\s*macro\\s+(\\w+)\\(([^)]*)\\)\\s*%\\}')\nfor p in pathlib.Path('templates').rglob('*.html'):\n    src = p.read_text()\n    sigs = {m.group(1): [p.strip().split('=')[0] for p in m.group(2).split(',') if p.strip()]\n            for m in macro_re.finditer(src)}\n    # naive check: look for kwarg= in calls and warn if not in sig\n    for call in re.finditer(r'(\\w+)\\([^)]*?(\\w+)=', src):\n        name, kw = call.group(1), call.group(2)\n        if name in sigs and '**' not in src and kw not in sigs[name]:\n            print(f'{p}: unexpected kwarg {kw} for macro {name}')","typeGuard":"def kwarg_allowed(macro_signature: list, has_catch_kwargs: bool, kw: str) -> bool:\n    return has_catch_kwargs or kw in macro_signature","tryCatchPattern":"# template authoring bug; fix the call site or add the parameter","preventionTips":["Pin the version of shared macro libraries so signatures do not drift unnoticed.","Add catch_kwargs to macros meant to receive arbitrary HTML attributes.","Render every macro with a representative call set in CI."],"tags":["jinja2","runtime","macro","kwargs","signature"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}