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
- Make createContainerExtension() return an instance of a class implementing ExtensionInterface
- Fix the auto-detected extension class name (Bundle\AcmeBundle\DependencyInjection\AcmeBundleExtension)
- Remove createContainerExtension() override if the bundle has no extension (return null instead of a bogus object)
- 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
- Follow the AcmeBundleExtension naming convention so auto-detection works
- Return null (not a bogus object) from createContainerExtension when there is no extension
- Boot the kernel in CI tests to catch bad bundles early
- Pin third-party bundle versions compatible with your Symfony DI version
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
- Users will expect the alias of the default extension of a…
- Controller " " has required constructor arguments and does…
- Controller " " cannot be fetched from the container because…
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)