symfony/http-kernel · error · LogicException

Extension " " must implement…

Error message

Extension "%s" must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.

What it means

Bundle::getContainerExtension() calls createContainerExtension() and requires the result (if non-null) to implement ExtensionInterface; otherwise it throws LogicException. This guards the convention that a bundle's DI extension class properly implements the framework contract.

Solutions

  1. Make createContainerExtension() return an instance of a class implementing ExtensionInterface
  2. Fix the auto-detected extension class name (Bundle\AcmeBundle\DependencyInjection\AcmeBundleExtension)
  3. Remove createContainerExtension() override if the bundle has no extension (return null instead of a bogus object)
  4. Check the third-party bundle's compatibility/version with your Symfony DI version

Example fix

// before
protected function createContainerExtension(): ?ExtensionInterface
{
    return new \stdClass(); // wrong type
}

// after
protected function createContainerExtension(): ?ExtensionInterface
{
    return new DependencyInjection\AcmeExtension();
}
Defensive patterns

Strategy: try-catch

Validate before calling

$ext = $bundle->getContainerExtension();
if (null !== $ext && !($ext instanceof \Symfony\Component\DependencyInjection\Extension\ExtensionInterface)) {
    throw new \LogicException(get_debug_type($ext).' must implement ExtensionInterface');
}

Try / catch

try { $kernel->boot(); } catch (\LogicException $e) { if (str_contains($e->getMessage(), 'must implement Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')) { /* inspect the offending bundle */ } }

Prevention

When it happens

Trigger: A bundle's createContainerExtension() (or the auto-resolved AcmeBundleExtension class) returns an object that doesn't implement ExtensionInterface — e.g. wrong class returned, a stub, or a misnamed extension class instantiated by mistake.

Common situations: Custom bundles with hand-written createContainerExtension returning the wrong object; refactors that renamed/moved the Extension class but kept a stale factory; copy-pasted bundle skeletons with placeholder extensions; third-party bundles incompatible with the current Symfony DI version.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13). Data as JSON: /api/errors/83a77609048d8469. Report an issue: GitHub.

Appendix: source

Thrown at Bundle/Bundle.php:40

 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Bundle extends BaseAbstractBundle implements BundleInterface
{
    private string $namespace;

    /**
     * Returns the bundle's container extension.
     *
     * @throws \LogicException
     */
    public function getContainerExtension(): ?ExtensionInterface
    {
        if (!isset($this->extension)) {
            $extension = $this->createContainerExtension();

            if (null !== $extension) {
                if (!$extension instanceof ExtensionInterface) {
                    throw new \LogicException(\sprintf('Extension "%s" must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', get_debug_type($extension)));
                }

                // check naming convention
                $basename = preg_replace('/Bundle$/', '', $this->getName());
                $expectedAlias = Container::underscore($basename);

                if ($expectedAlias != $extension->getAlias()) {
                    throw new \LogicException(\sprintf('Users will expect the alias of the default extension of a bundle to be the underscored version of the bundle name ("%s"). You can override "Bundle::getContainerExtension()" if you want to use "%s" or another alias.', $expectedAlias, $extension->getAlias()));
                }

                $this->extension = $extension;
            } else {
                $this->extension = false;
            }
        }

        return $this->extension ?: null;
    }

View on GitHub (pinned to aa3a39d728)