twigphp/Twig · error · LogicException
Unable to add filter
Error message
Unable to add filter "%s" as extensions have already been initialized.
What it means
TwigFilter registration goes through ExtensionSet::addFilter, which is only valid before extension initialization. Once initialized, the filter table is built and frozen, so late addFilter calls throw this LogicException.
Solutions
- Register all filters immediately after Environment construction.
- Move filters into an Extension class added at construction time.
- Instantiate a fresh Environment when a different filter set is needed.
- In frameworks, expose the filter via an extension service instead of direct addFilter calls.
Example fix
// before
$twig = new Environment($loader);
$twig->render('x.twig');
$twig->addFilter(new TwigFilter('shout', fn($s) => strtoupper($s)));
// after
$twig = new Environment($loader);
$twig->addFilter(new TwigFilter('shout', fn($s) => strtoupper($s)));
$twig->render('x.twig'); Defensive patterns
Strategy: try-catch
Validate before calling
// register before first use
if (!isset($GLOBALS['twig_initialized'])) {
$twig->addFilter($filter);
} Try / catch
try { $twig->addFilter($filter); } catch (\LogicException $e) {
if (str_contains($e->getMessage(), 'already been initialized')) {
// defer to a new Environment or move registration to bootstrap
} else { throw $e; }
} Prevention
- Register all filters during bootstrap, before any render/compile call.
- Package filters in an Extension class added at construction time.
- Avoid conditionally adding filters after partial page renders.
- Audit request lifecycle hooks for late twig mutations.
When it happens
Trigger: Calling $twig->addFilter(...) after any render/loadTemplate/getFilter call initialized the extension set; adding filters conditionally after an earlier template was rendered in the same request.
Common situations: Registering filters in a middleware/controller after twig rendered an error page; scripts that render a first template early then set up custom filters; shared Environment objects in test suites mutated mid-suite.
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 function
- Unable to add a node visitor as extensions have already…
- The " " filter is part of the , which is not…
- The "replace" filter expects a sequence or a mapping, got
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/8e1128f5fe94272d.
Report an issue: GitHub.
Appendix: source
Thrown at src/ExtensionSet.php:225
return $function;
}
}
return null;
}
/**
* @param callable(string): (TwigFunction|false) $callable
*/
public function registerUndefinedFunctionCallback(callable $callable): void
{
$this->functionCallbacks[] = $callable;
}
public function addFilter(TwigFilter $filter): void
{
if ($this->initialized) {
throw new \LogicException(\sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
}
$this->staging->addFilter($filter);
}
/**
* @return TwigFilter[]
*/
public function getFilters(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->filters;
}
public function getFilter(string $name): ?TwigFilterView on GitHub (pinned to a414c3a491)