twigphp/Twig · error · LogicException
Unable to add a node visitor as extensions have already…
Error message
Unable to add a node visitor as extensions have already been initialized.
What it means
Node visitors (NodeVisitorInterface) are collected during extension initialization and applied at compile time. ExtensionSet::addNodeVisitor rejects late additions with this LogicException because the compilation pipeline may already have run (or be cached), making the visitor addition ineffective — so Twig fails loudly instead.
Solutions
- Add node visitors at bootstrap, right after creating the Environment, before any compile/render.
- Attach the visitor via a custom Extension class registered at construction.
- Use a fresh Environment when visitors must differ per run.
- Verify with debug tooling (e.g. Twig profiler) whether an earlier render already initialized extensions.
Example fix
// before
$twig = new Environment($loader);
$twig->render('a.twig');
$twig->addNodeVisitor(new MyVisitor()); // too late
// after
$twig = new Environment($loader);
$twig->addNodeVisitor(new MyVisitor());
$twig->render('a.twig'); Defensive patterns
Strategy: try-catch
Validate before calling
// node visitors must be added before first compile; do it at construction time $twig = new \Twig\Environment($loader); $twig->addNodeVisitor($visitor); // before any render/loadTemplate
Try / catch
try { $twig->addNodeVisitor($visitor); } catch (\LogicException $e) {
if (str_contains($e->getMessage(), 'already been initialized')) {
$twig = new \Twig\Environment($loader);
$twig->addNodeVisitor($visitor);
} else { throw $e; }
} Prevention
- Attach node visitors at Environment construction time, never after first render.
- Ship visitors inside an Extension class for framework-managed registration.
- Keep profiling/debug visitors in a separate boot path that runs before rendering.
- Avoid sharing one Environment across configurations needing different visitors.
When it happens
Trigger: Calling $twig->addNodeVisitor(...) after the extension set was initialized by a previous render/compile/loadTemplate call; adding visitors from a runtime hook that executes post-compilation.
Common situations: Profiling/optimization visitors added after a first render warmed caches; debug visitors registered conditionally mid-request; test bootstrap adding visitors per-test to a cached 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 function
- Unable to add filter
- The " " extension is not enabled.
- Tag " " is already registered.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/f204b5f2877e2082.
Report an issue: GitHub.
Appendix: source
Thrown at src/ExtensionSet.php:281
return $filter;
}
}
return null;
}
/**
* @param callable(string): (TwigFilter|false) $callable
*/
public function registerUndefinedFilterCallback(callable $callable): void
{
$this->filterCallbacks[] = $callable;
}
public function addNodeVisitor(NodeVisitorInterface $visitor): void
{
if ($this->initialized) {
throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.');
}
$this->staging->addNodeVisitor($visitor);
}
/**
* @return NodeVisitorInterface[]
*/
public function getNodeVisitors(): array
{
if (!$this->initialized) {
$this->initExtensions();
}
return $this->visitors;
}
public function addTokenParser(TokenParserInterface $parser): voidView on GitHub (pinned to a414c3a491)