{"record":{"id":"f204b5f2877e2082","repo":"twigphp/Twig","slug":"unable-to-add-a-node-visitor-as-extensions-have-already-been","errorCode":null,"errorMessage":"Unable to add a node visitor as extensions have already been initialized.","messagePattern":"Unable to add a node visitor as extensions have already been initialized\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/ExtensionSet.php","lineNumber":281,"sourceCode":"                return $filter;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param callable(string): (TwigFilter|false) $callable\n     */\n    public function registerUndefinedFilterCallback(callable $callable): void\n    {\n        $this->filterCallbacks[] = $callable;\n    }\n\n    public function addNodeVisitor(NodeVisitorInterface $visitor): void\n    {\n        if ($this->initialized) {\n            throw new \\LogicException('Unable to add a node visitor as extensions have already been initialized.');\n        }\n\n        $this->staging->addNodeVisitor($visitor);\n    }\n\n    /**\n     * @return NodeVisitorInterface[]\n     */\n    public function getNodeVisitors(): array\n    {\n        if (!$this->initialized) {\n            $this->initExtensions();\n        }\n\n        return $this->visitors;\n    }\n\n    public function addTokenParser(TokenParserInterface $parser): void","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/ExtensionSet.php#L263-L299","documentation":"Node visitors (NodeVisitorInterface) are collected during extension initialization and applied at compile time. ExtensionSet::addNodeVisitor rejects late additions with this LogicException because the compilation pipeline may already have run (or be cached), making the visitor addition ineffective — so Twig fails loudly instead.","triggerScenarios":"Calling $twig->addNodeVisitor(...) after the extension set was initialized by a previous render/compile/loadTemplate call; adding visitors from a runtime hook that executes post-compilation.","commonSituations":"Profiling/optimization visitors added after a first render warmed caches; debug visitors registered conditionally mid-request; test bootstrap adding visitors per-test to a cached Environment.","solutions":["Add node visitors at bootstrap, right after creating the Environment, before any compile/render.","Attach the visitor via a custom Extension class registered at construction.","Use a fresh Environment when visitors must differ per run.","Verify with debug tooling (e.g. Twig profiler) whether an earlier render already initialized extensions."],"exampleFix":"// before\n$twig = new Environment($loader);\n$twig->render('a.twig');\n$twig->addNodeVisitor(new MyVisitor()); // too late\n\n// after\n$twig = new Environment($loader);\n$twig->addNodeVisitor(new MyVisitor());\n$twig->render('a.twig');","handlingStrategy":"try-catch","validationCode":"// node visitors must be added before first compile; do it at construction time\n$twig = new \\Twig\\Environment($loader);\n$twig->addNodeVisitor($visitor); // before any render/loadTemplate","typeGuard":null,"tryCatchPattern":"try { $twig->addNodeVisitor($visitor); } catch (\\LogicException $e) {\n    if (str_contains($e->getMessage(), 'already been initialized')) {\n        $twig = new \\Twig\\Environment($loader);\n        $twig->addNodeVisitor($visitor);\n    } else { throw $e; }\n}","preventionTips":["Attach node visitors at Environment construction time, never after first render.","Ship visitors inside an Extension class for framework-managed registration.","Keep profiling/debug visitors in a separate boot path that runs before rendering.","Avoid sharing one Environment across configurations needing different visitors."],"tags":["twig","extension","node-visitor","initialization-order"],"backgroundTag":"invalid-state-transition","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}