symfony/routing · error · InvalidArgumentException
Attributes from class
Error message
Attributes from class "%s" cannot be read as it is abstract.
What it means
AttributeClassLoader::load() rejects abstract classes because attributes (Route/condition decorators) on an abstract class cannot yield an instantiable controller route set in the normal way; reading them is considered a configuration mistake.
Solutions
- Load a concrete (non-abstract) controller class
- Exclude abstract classes from your controller-discovery list (e.g. instanceof / isAbstract filter)
- Move route attributes from the abstract base to concrete subclasses, or use a parent-class-aware loader
Example fix
// before $loader->load(AbstractApiController::class); // abstract // after $loader->load(ProductApiController::class); // concrete subclass
Defensive patterns
Strategy: validation
Validate before calling
$ref = new \ReflectionClass($class);
if ($ref->isAbstract()) {
throw new \InvalidArgumentException("Cannot load attributes from abstract class '$class'");
} Type guard
function isConcreteClass(string $class): bool {
return class_exists($class) && !(new \ReflectionClass($class))->isAbstract();
} Try / catch
try {
$collection = $loader->load($class);
} catch (\InvalidArgumentException $e) {
// skip abstract classes discovered by the scanner
} Prevention
- Filter abstract classes out of controller auto-discovery lists
- Only reference concrete controllers in route configuration
- Add a unit test asserting all scanned controller classes are instantiable
When it happens
Trigger: $loader->load(AbstractControllerBase::class) where the class is declared abstract — e.g. pointing the loader at a shared base controller instead of a concrete one.
Common situations: Loading a base controller class with common route attributes; auto-discovery mistakenly including abstract classes in the controller scan list.
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
- Class " " does not exist.
- Route aliases cannot be used on non-invokable class
- The " ()" method must not be called.
- Case must be a "BackedEnum" instance
- " :: " is not a case of " ".
AI-assisted analysis of symfony/routing@83fa223250 (2026-09-14).
Data as JSON: /api/errors/8045e8a86d02c9cc.
Report an issue: GitHub.
Appendix: source
Thrown at Loader/AttributeClassLoader.php:85
* Sets the attribute class to read route properties from.
*/
public function setRouteAttributeClass(string $class): void
{
$this->routeAttributeClass = $class;
}
/**
* @throws \InvalidArgumentException When route can't be parsed
*/
public function load(mixed $class, ?string $type = null): RouteCollection
{
if (!class_exists($class)) {
throw new \InvalidArgumentException(\sprintf('Class "%s" does not exist.', $class));
}
$class = new \ReflectionClass($class);
if ($class->isAbstract()) {
throw new \InvalidArgumentException(\sprintf('Attributes from class "%s" cannot be read as it is abstract.', $class->getName()));
}
$globals = $this->getGlobals($class);
$collection = new RouteCollection();
$collection->addResource(new ReflectionClassResource($class));
if ($globals['env'] && !\in_array($this->env, $globals['env'], true)) {
return $collection;
}
$fqcnAlias = false;
if (!$class->hasMethod('__invoke')) {
foreach ($this->getAttributes($class) as $attr) {
if ($attr->aliases) {
throw new InvalidArgumentException(\sprintf('Route aliases cannot be used on non-invokable class "%s".', $class->getName()));
}
}
}
View on GitHub (pinned to 83fa223250)