{"record":{"id":"f7da00c5a6ae01c9","repo":"twigphp/Twig","slug":"unable-to-add-a-token-parser-as-extensions-have-already-been","errorCode":null,"errorMessage":"Unable to add a token parser as extensions have already been initialized.","messagePattern":"Unable to add a token parser as extensions have already been initialized\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/ExtensionSet.php","lineNumber":302,"sourceCode":"        $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\n    {\n        if ($this->initialized) {\n            throw new \\LogicException('Unable to add a token parser as extensions have already been initialized.');\n        }\n\n        $this->staging->addTokenParser($parser);\n    }\n\n    /**\n     * @return TokenParserInterface[]\n     */\n    public function getTokenParsers(): array\n    {\n        if (!$this->initialized) {\n            $this->initExtensions();\n        }\n\n        return $this->parsers;\n    }\n\n    public function getTokenParser(string $name): ?TokenParserInterface","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/ExtensionSet.php#L284-L320","documentation":"Twig's ExtensionSet throws this LogicException when addTokenParser() is called after the extension environment has been initialized. Token parsers must be registered during environment setup, before any template is loaded or rendered, because the parser registry is frozen once extensions are initialized.","triggerScenarios":"Calling addTokenParser() on the ExtensionSet (or via an extension wired to it) after the Twig Environment booted: after any render/loadTemplate/getTemplate call or any access that triggers initExtensions(). Typically registering a custom token parser lazily inside a request handler or render hook.","commonSituations":"Registering an extension/parser from a framework bundle after container boot and Twig warmup; mutating a shared/cached Twig Environment at request runtime; calling addTokenParser in code that runs after a first render in the same process.","solutions":["Register the token parser (via its extension) immediately after constructing the Environment and before any loadTemplate/render call.","Wrap the parser in an AbstractExtension::getTokenParsers() and add that extension up front with $twig->addExtension().","In frameworks (e.g. Symfony), register the extension as a twig.extension tagged service so it is added during container setup.","If late registration is unavoidable, create a fresh Environment with the parser included instead of mutating the initialized one."],"exampleFix":"// before\n$twig = new \\Twig\\Environment($loader);\n$twig->render('home.twig'); // environment now initialized\n$twig->getExtension(ExtensionSet::class)->addTokenParser(new MyParser());\n\n// after\n$twig = new \\Twig\\Environment($loader);\n$twig->addExtension(new MyExtension()); // getTokenParsers() supplies the parser pre-init\n$twig->render('home.twig');","handlingStrategy":"validation","validationCode":"// Track initialization yourself and register before first use:\n$twig = new \\Twig\\Environment($loader);\n$twig->addExtension(new MyExtension()); // must precede any render/loadTemplate\n$twig->render('template.twig');","typeGuard":null,"tryCatchPattern":"try {\n    $twig->getExtension(\\Twig\\ExtensionSet::class)->addTokenParser($parser);\n} catch (\\LogicException $e) {\n    throw new \\RuntimeException('Token parser registered too late: register it before the first render', 0, $e);\n}","preventionTips":["Register all extensions/parsers immediately after Environment construction, before any render","In frameworks, use the extension tagging mechanism (e.g. twig.extension services) instead of imperative late calls","Never mutate a shared/cached Twig instance at request runtime","Centralize environment setup in a factory that fully configures it before returning"],"tags":["php","twig","lifecycle","extensions"],"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"}