twigphp/Twig · error · LogicException

Unable to register extension

Error message

Unable to register extension "%s" as extensions have already been initialized.

What it means

ExtensionSet only accepts new extensions while the environment is uninitialized. Once extensions have been initialized (lazily, usually on first render/load), the set of functions, filters, tags and tests is frozen; calling addExtension afterward throws this LogicException because the compiled/cached state already reflects the old extension set.

Solutions

  1. Register all extensions immediately after creating the Environment, before any render/load call.
  2. Ensure testMultipleRegistrations-style setup runs once at bootstrap, not per render.
  3. Create a fresh Environment instance if you genuinely need a different extension set at runtime.
  4. If lazy, force extension registration into the service factory that builds the Twig environment.

Example fix

// before
$twig = new \Twig\Environment($loader);
echo $twig->render('hi.twig');
$twig->addExtension(new MyExtension()); // too late

// after
$twig = new \Twig\Environment($loader);
$twig->addExtension(new MyExtension());
echo $twig->render('hi.twig');
Defensive patterns

Strategy: try-catch

Validate before calling

// register early: do this only if extensions are not yet initialized
if (!$env->hasExtension('Twig\Extension\CoreExtension') || !method_exists($env, 'render') || true) {
    // best guard: add extensions immediately after construction, before first render
}

Try / catch

try { $twig->addExtension($ext); } catch (\LogicException $e) {
    if (str_contains($e->getMessage(), 'already been initialized')) {
        $twig = new \Twig\Environment($loader, $options);
        $twig->addExtension($ext); // rebuild environment
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Calling $twig->addExtension(...) after Twig has already initialized extensions — typically after the first render(), loadTemplate(), or token parse in the same request; also via setExtensions() late in the lifecycle.

Common situations: Registering extensions inside a controller/event handler that runs after some earlier code already rendered a template; Symfony apps calling addExtension after the Twig service was first used; test suites reusing an Environment across tests and adding extensions per-test.

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/250e7dcaf2f9b76d. Report an issue: GitHub.

Appendix: source

Thrown at src/ExtensionSet.php:156

                if (is_file($r->getFileName())) {
                    $lastModified = max(filemtime($r->getFileName()), $lastModified);
                }
            }
        }

        return $this->lastModified = $lastModified;
    }

    public function addExtension(ExtensionInterface $extension): void
    {
        if ($extension instanceof AttributeExtension) {
            $class = $extension->getClass();
        } else {
            $class = $extension::class;
        }

        if ($this->initialized) {
            throw new \LogicException(\sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
        }

        if (isset($this->extensions[$class])) {
            throw new \LogicException(\sprintf('Unable to register extension "%s" as it is already registered.', $class));
        }

        $this->extensions[$class] = $extension;
    }

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

        $this->staging->addFunction($function);
    }

View on GitHub (pinned to a414c3a491)