{"record":{"id":"3523b402b1f6a12f","repo":"twigphp/Twig","slug":"unable-to-add-test-s-as-extensions-have-already-been","errorCode":null,"errorMessage":"Unable to add test \"%s\" as extensions have already been initialized.","messagePattern":"Unable to add test \"(.+?)\" as extensions have already been initialized\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/ExtensionSet.php","lineNumber":380,"sourceCode":"            $globals = array_merge($globals, $extension->getGlobals());\n        }\n\n        if ($this->initialized) {\n            $this->globals = $globals;\n        }\n\n        return $globals;\n    }\n\n    public function resetGlobals(): void\n    {\n        $this->globals = null;\n    }\n\n    public function addTest(TwigTest $test): void\n    {\n        if ($this->initialized) {\n            throw new \\LogicException(\\sprintf('Unable to add test \"%s\" as extensions have already been initialized.', $test->getName()));\n        }\n\n        $this->staging->addTest($test);\n    }\n\n    /**\n     * @return TwigTest[]\n     */\n    public function getTests(): array\n    {\n        if (!$this->initialized) {\n            $this->initExtensions();\n        }\n\n        return $this->tests;\n    }\n\n    public function getTest(string $name): ?TwigTest","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/ExtensionSet.php#L362-L398","documentation":"ExtensionSet throws this LogicException when addTest() is invoked after extensions have been initialized. Custom TwigTest instances (expression tests like `is odd`) must be registered during setup; the test registry is frozen once the environment initializes so template compilation sees a stable set.","triggerScenarios":"Calling addTest() on the ExtensionSet after initExtensions() ran — i.e., after any render/loadTemplate/getTemplate call or after earlier access to filters/tests/functions/globals. Common with lazy runtime registration of custom tests.","commonSituations":"Adding a custom test lazily at runtime; registering tests from a service after the Twig environment warmed; mutating a shared/cached environment after the first render; framework apps where the environment boots before the extension that adds the test runs.","solutions":["Declare the TwigTest in AbstractExtension::getTests() and register that extension with addExtension() before any render/loadTemplate call.","Call addTest() only during environment construction, never after the first render or template load.","In Symfony or similar, expose the test via a twig.extension tagged service so registration happens during environment boot.","If late registration is required, rebuild a new Environment with the test included rather than mutating the initialized one."],"exampleFix":"// before\n$twig = new \\Twig\\Environment($loader);\n$twig->render('x.twig');\n$twig->getExtension(ExtensionSet::class)->addTest(new \\Twig\\TwigTest('even2', fn ($v) => $v % 2 === 0));\n\n// after\nclass MyExtension extends \\Twig\\Extension\\AbstractExtension {\n    public function getTests(): array {\n        return [new \\Twig\\TwigTest('even2', fn ($v) => $v % 2 === 0)];\n    }\n}\n$twig = new \\Twig\\Environment($loader);\n$twig->addExtension(new MyExtension());\n$twig->render('x.twig');","handlingStrategy":"validation","validationCode":"// Ensure the extension with the test is registered before first use:\n$twig = new \\Twig\\Environment($loader);\n$twig->addExtension(new MyExtension()); // getTests() supplied here\n$twig->render('template.twig'); // only afterwards","typeGuard":null,"tryCatchPattern":"try {\n    $twig->getExtension(\\Twig\\ExtensionSet::class)->addTest($test);\n} catch (\\LogicException $e) {\n    throw new \\RuntimeException('Twig test must be registered before environment initialization', 0, $e);\n}","preventionTips":["Declare custom tests in AbstractExtension::getTests() and register the extension up front","Register all extensions before the first loadTemplate/getTemplate/render call","Avoid storing long-lived environments and mutating them later; rebuild instead","Use a bootstrap/factory function that returns a fully configured environment"],"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"}