nodejs/node · error · TemplateRuntimeError
cannot assign attribute on non-namespace object
Error message
cannot assign attribute on non-namespace object
What it means
Compiled-in runtime guard emitted by visit_NSRef when a template uses namespace attribute assignment (`{% set ns.foo = ... %}`) but the target is not a Jinja2 Namespace object at render time. NSRef nodes are emitted for `set x.y = value`; before performing the assignment the generated code asserts isinstance(ref, Namespace).
Source
Thrown at tools/inspector_protocol/jinja2/compiler.py:1425
# instruction indicates a parameter which are always defined.
if node.ctx == 'load':
load = frame.symbols.find_load(ref)
if not (load is not None and load[0] == VAR_LOAD_PARAMETER and \
not self.parameter_is_undeclared(ref)):
self.write('(undefined(name=%r) if %s is missing else %s)' %
(node.name, ref, ref))
return
self.write(ref)
def visit_NSRef(self, node, frame):
# NSRefs can only be used to store values; since they use the normal
# `foo.bar` notation they will be parsed as a normal attribute access
# when used anywhere but in a `set` context
ref = frame.symbols.ref(node.name)
self.writeline('if not isinstance(%s, Namespace):' % ref)
self.indent()
self.writeline('raise TemplateRuntimeError(%r)' %
'cannot assign attribute on non-namespace object')
self.outdent()
self.writeline('%s[%r]' % (ref, node.attr))
def visit_Const(self, node, frame):
val = node.as_const(frame.eval_ctx)
if isinstance(val, float):
self.write(str(val))
else:
self.write(repr(val))
def visit_TemplateData(self, node, frame):
try:
self.write(repr(node.as_const(frame.eval_ctx)))
except nodes.Impossible:
self.write('(Markup if context.eval_ctx.autoescape else identity)(%r)'
% node.data)
View on GitHub (pinned to 1b2de5e052)
Solutions
- Initialize with `{% set ns = namespace(...) %}` before any `{% set ns.x = ... %}`.
- If you intended a dict, use bracket access (`{% set _ = mydict.update(...) %}`) rather than attribute-set syntax.
- Make sure the name used on the left of the dot is the same one bound to namespace().
Example fix
{# before #}
{% set item.count = item.count + 1 %}
{# after #}
{% set item = namespace(count=0) %}
{% set item.count = item.count + 1 %} Defensive patterns
Strategy: validation
Validate before calling
from jinja2 import Namespace
def ensure_namespace(var):
return var if isinstance(var, Namespace) else Namespace() Type guard
from jinja2 import Namespace
def is_namespace(v) -> bool:
return isinstance(v, Namespace) Prevention
- Always initialize `{% set ns = namespace(...) %}` before `set ns.x = ...`.
- Do not reuse a namespace name for a non-namespace value mid-template.
- Use dicts with bracket access if you did not mean attribute assignment.
When it happens
Trigger: Writing `{% set myvar.attr = 1 %}` where myvar was never initialized as a Namespace (it is a plain dict, a string, None, or undefined); shadowing a namespace variable with a non-namespace value partway through a template.
Common situations: Forgetting the `{% set ns = namespace() %}` initialization before `{% set ns.counter = 0 %}`; expecting dicts to support attribute assignment; using namespace mutation to carry state across loop iterations but reassigning ns to something else first.
Related errors
- Template module attribute is unavailable in async mode
- Loop length for some iterators cannot be lazily calculated i
- extended multiple times
- no loader for this environment specified
- Tried to select from an empty list of templates.
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/fd3f7d25d5638f02.
Report an issue: GitHub.