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

  1. Register all filters immediately after Environment construction.
  2. Move filters into an Extension class added at construction time.
  3. Instantiate a fresh Environment when a different filter set is needed.
  4. 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

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


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): ?TwigFilter

View on GitHub (pinned to a414c3a491)