nodejs/node · error · TypeError
can't create custom node types
Error message
can't create custom node types
What it means
NodeType.__new__ is monkey-patched to _failing_new at the end of nodes.py, so any attempt to create a new instance of NodeType or any subclass that does not override __new__ raises TypeError('can't create custom node types'). This is a deliberate guard: the Jinja2 AST node set is closed; only nodes defined inside jinja2.nodes are constructible, and user code is not allowed to mint custom node types.
Source
Thrown at tools/inspector_protocol/jinja2/nodes.py:998
Example to change the `autoescape` setting::
EvalContextModifier(options=[Keyword('autoescape', Const(True))])
"""
fields = ('options',)
class ScopedEvalContextModifier(EvalContextModifier):
"""Modifies the eval context and reverts it later. Works exactly like
:class:`EvalContextModifier` but will only modify the
:class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
"""
fields = ('body',)
# make sure nobody creates custom nodes
def _failing_new(*args, **kwargs):
raise TypeError('can\'t create custom node types')
NodeType.__new__ = staticmethod(_failing_new); del _failing_new
View on GitHub (pinned to 1b2de5e052)
Solutions
- Do not subclass Jinja2 nodes; instead represent custom logic with existing node types or via extensions that hook the compiler.
- If you need a marker class, subclass object (or a plain base) rather than NodeType.
- For (de)serialization, use a format that does not reconstruct nodes via __new__ (e.g. recompile source rather than pickling ASTs).
- If absolutely necessary for a fork, override __new__ on your subclass to call object.__new__ - unsupported and version-fragile.
Example fix
// before
class MyNode(nodes.Expr):
fields = ('value',)
instance = MyNode() # raises
// after
class MyMarker(object): # not a Jinja2 node
pass
# express custom behavior through an extension + existing node types instead Defensive patterns
Strategy: validation
Validate before calling
from jinja2 import nodes
import typing
cls = MyCandidateClass
if isinstance(cls, type) and issubclass(cls, nodes.NodeType):
raise TypeError('do not subclass jinja2 NodeType; Jinja2 nodes are a closed set') Type guard
def is_jinja_node_class(cls) -> bool:
from jinja2 import nodes
return isinstance(cls, type) and issubclass(cls, nodes.NodeType) Try / catch
# n/a - the failing __new__ is intentional; do not catch # fix the design instead of subclassing NodeType
Prevention
- Express custom template behavior through Jinja2 extensions, not new node types.
- Use marker classes that subclass object, not NodeType, when you need a tag type.
- Avoid pickling Jinja2 ASTs; recompile from source on load.
When it happens
Trigger: Defining a subclass of nodes.Node / nodes.Expr and trying to instantiate it (the subclass inherits the failing __new__). Calling NodeType() directly. A pickling/unpickling round-trip that invokes __new__ for an unknown node subclass registered externally.
Common situations: Extensions or compiler plugins that attempt to introduce new AST node types. Copy/paste of node definitions expecting them to be instantiable. PyInstaller / multiprocessing spawning that rebuilds nodes via __new__.
Related errors
- Can't compile non template nodes
- Can't create internal names. Use the `free_identifier` meth
- Failed to parse config file "%s": %s
- Failed to parse isolate map file "%s": %s
- Unknown AST node at key path '%s': %s
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/59c94591dbf93909.
Report an issue: GitHub.