twigphp/Twig · error · LogicException

Unable to add test " " as extensions have already been…

Error message

Unable to add test "%s" as extensions have already been initialized.

What it means

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.

Solutions

  1. Declare the TwigTest in AbstractExtension::getTests() and register that extension with addExtension() before any render/loadTemplate call.
  2. Call addTest() only during environment construction, never after the first render or template load.
  3. In Symfony or similar, expose the test via a twig.extension tagged service so registration happens during environment boot.
  4. If late registration is required, rebuild a new Environment with the test included rather than mutating the initialized one.

Example fix

// before
$twig = new \Twig\Environment($loader);
$twig->render('x.twig');
$twig->getExtension(ExtensionSet::class)->addTest(new \Twig\TwigTest('even2', fn ($v) => $v % 2 === 0));

// after
class MyExtension extends \Twig\Extension\AbstractExtension {
    public function getTests(): array {
        return [new \Twig\TwigTest('even2', fn ($v) => $v % 2 === 0)];
    }
}
$twig = new \Twig\Environment($loader);
$twig->addExtension(new MyExtension());
$twig->render('x.twig');
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the extension with the test is registered before first use:
$twig = new \Twig\Environment($loader);
$twig->addExtension(new MyExtension()); // getTests() supplied here
$twig->render('template.twig'); // only afterwards

Try / catch

try {
    $twig->getExtension(\Twig\ExtensionSet::class)->addTest($test);
} catch (\LogicException $e) {
    throw new \RuntimeException('Twig test must be registered before environment initialization', 0, $e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13). Data as JSON: /api/errors/3523b402b1f6a12f. Report an issue: GitHub.

Appendix: source

Thrown at src/ExtensionSet.php:380

            $globals = array_merge($globals, $extension->getGlobals());
        }

        if ($this->initialized) {
            $this->globals = $globals;
        }

        return $globals;
    }

    public function resetGlobals(): void
    {
        $this->globals = null;
    }

    public function addTest(TwigTest $test): void
    {
        if ($this->initialized) {
            throw new \LogicException(\sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
        }

        $this->staging->addTest($test);
    }

    /**
     * @return TwigTest[]
     */
    public function getTests(): array
    {
        if (!$this->initialized) {
            $this->initExtensions();
        }

        return $this->tests;
    }

    public function getTest(string $name): ?TwigTest

View on GitHub (pinned to a414c3a491)