twigphp/Twig · error · LogicException
Unable to add function
Error message
Unable to add function "%s" as extensions have already been initialized.
What it means
Like addExtension, adding a Twig function is only allowed before extensions are initialized. After initialization the function table is built and frozen (and may be cached), so ExtensionSet::addFunction throws this LogicException for late additions.
Solutions
- Call addFunction right after constructing the Environment, before rendering anything.
- Alternatively wrap the function in a proper Extension class registered at construction time.
- Create a new Environment if late registration is truly required.
- In Symfony, register the function via a TwigExtension service so the framework adds it at boot.
Example fix
// before
$twig = new Environment($loader);
$twig->render('page.twig');
$twig->addFunction(new TwigFunction('price', fn($v) => $v * 1.2));
// after
$twig = new Environment($loader);
$twig->addFunction(new TwigFunction('price', fn($v) => $v * 1.2));
$twig->render('page.twig'); Defensive patterns
Strategy: try-catch
Validate before calling
// guard: register before initialization
$functionsAdded = false;
function addFunctionEarly(\Twig\Environment $twig, \Twig\TwigFunction $fn): void {
global $functionsAdded;
if ($functionsAdded) { throw new \LogicException('Too late to add functions'); }
} Try / catch
try { $twig->addFunction($fn); } catch (\LogicException $e) {
if (str_contains($e->getMessage(), 'already been initialized')) {
// move to bootstrap or recreate the environment
} else { throw $e; }
} Prevention
- Add all functions right after Environment construction.
- Wrap functions in an Extension class so the framework registers them at boot.
- Do not render any template before finishing Twig setup.
- In tests, build a fresh Environment whenever functions change.
When it happens
Trigger: Calling $twig->addFunction(...) after the environment has been used (render/loadTemplate/getTokenParsers) which triggers lazy initialization; also calling it on an ExtensionSet already flagged initialized.
Common situations: Defining twig functions in a listener that fires post-boot; adding functions conditionally inside a loop that runs after first render; tests adding functions per-test on a shared Environment.
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
- Unable to register extension
- Unable to add filter
- Unable to add a node visitor as extensions have already…
- The " " function is part of the , which is not…
- The " " extension is not enabled.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/5a92b2627e279104.
Report an issue: GitHub.
Appendix: source
Thrown at src/ExtensionSet.php:169
} 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);
}
/**
* @return TwigFunction[]
*/
public function getFunctions(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->functions;
}
public function getFunction(string $name): ?TwigFunctionView on GitHub (pinned to a414c3a491)