{"record":{"id":"59c94591dbf93909","repo":"nodejs/node","slug":"can-t-create-custom-node-types","errorCode":null,"errorMessage":"can't create custom node types","messagePattern":"can't create custom node types","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"tools/inspector_protocol/jinja2/nodes.py","lineNumber":998,"sourceCode":"\n    Example to change the `autoescape` setting::\n\n        EvalContextModifier(options=[Keyword('autoescape', Const(True))])\n    \"\"\"\n    fields = ('options',)\n\n\nclass ScopedEvalContextModifier(EvalContextModifier):\n    \"\"\"Modifies the eval context and reverts it later.  Works exactly like\n    :class:`EvalContextModifier` but will only modify the\n    :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.\n    \"\"\"\n    fields = ('body',)\n\n\n# make sure nobody creates custom nodes\ndef _failing_new(*args, **kwargs):\n    raise TypeError('can\\'t create custom node types')\nNodeType.__new__ = staticmethod(_failing_new); del _failing_new\n","sourceCodeStart":980,"sourceCodeEnd":1000,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/inspector_protocol/jinja2/nodes.py#L980-L1000","documentation":"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.","triggerScenarios":"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.","commonSituations":"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__.","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."],"exampleFix":"// before\nclass MyNode(nodes.Expr):\n    fields = ('value',)\ninstance = MyNode()  # raises\n// after\nclass MyMarker(object):  # not a Jinja2 node\n    pass\n# express custom behavior through an extension + existing node types instead","handlingStrategy":"validation","validationCode":"from jinja2 import nodes\nimport typing\ncls = MyCandidateClass\nif isinstance(cls, type) and issubclass(cls, nodes.NodeType):\n    raise TypeError('do not subclass jinja2 NodeType; Jinja2 nodes are a closed set')","typeGuard":"def is_jinja_node_class(cls) -> bool:\n    from jinja2 import nodes\n    return isinstance(cls, type) and issubclass(cls, nodes.NodeType)","tryCatchPattern":"# n/a - the failing __new__ is intentional; do not catch\n# fix the design instead of subclassing NodeType","preventionTips":["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."],"tags":["jinja2","ast","node-type","sealed-hierarchy","monkeypatch"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}