doctrine/orm · error · LogicException
The attribute "%s" is not repeatable. Call getPropertyAttrib
Error message
The attribute "%s" is not repeatable. Call getPropertyAttribute() instead.
What it means
The mirror image of getPropertyAttribute()'s guard: getPropertyAttributeCollection() returns a RepeatableAttributeCollection and is only valid for mapping attribute classes declared with Attribute::IS_REPEATABLE. Passing a non-repeatable attribute class (which can appear at most once per property) throws LogicException pointing back to the singular getPropertyAttribute().
Source
Thrown at src/Mapping/Driver/AttributeReader.php:87
));
}
return $this->getPropertyAttributes($property)[$attributeName] ?? null;
}
/**
* @param class-string<T> $attributeName The name of the annotation.
*
* @return RepeatableAttributeCollection<T>
*
* @template T of MappingAttribute
*/
public function getPropertyAttributeCollection(
ReflectionProperty $property,
string $attributeName,
): RepeatableAttributeCollection {
if (! $this->isRepeatable($attributeName)) {
throw new LogicException(sprintf(
'The attribute "%s" is not repeatable. Call getPropertyAttribute() instead.',
$attributeName,
));
}
return $this->getPropertyAttributes($property)[$attributeName] ?? new RepeatableAttributeCollection();
}
/**
* @param array<ReflectionAttribute> $attributes
*
* @return class-string-map<T, T|RepeatableAttributeCollection<T>>
*
* @template T of MappingAttribute
*/
private function convertToAttributeInstances(array $attributes): array
{
$instances = [];View on GitHub (pinned to d9b9ff7301)
Solutions
- Call getPropertyAttribute($property, $attribute) instead and handle the null return when the attribute is absent.
- If the attribute genuinely needs to be repeatable, declare it as #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)].
- Dispatch on the IS_REPEATABLE flag (via reflection) when writing generic code that handles both kinds.
Example fix
// before $col = $reader->getPropertyAttributeCollection($property, Mapping\Column::class); // LogicException: not repeatable // after $col = $reader->getPropertyAttribute($property, Mapping\Column::class); // Column|null
Defensive patterns
Strategy: type-guard
Type guard
/** @param class-string $attribute */
function isRepeatableAttribute(string $attribute): bool
{
$flags = (new ReflectionClass($attribute))
->getAttributes(Attribute::class)[0]?->getArguments()[0] ?? 0;
return ($flags & Attribute::IS_REPEATABLE) !== 0;
}
if (! isRepeatableAttribute($name)) {
$single = $reader->getPropertyAttribute($property, $name);
} Prevention
- Use the singular getter unless the attribute is declared IS_REPEATABLE.
- For generic walkers, dispatch on the IS_REPEATABLE flag.
- Treat AttributeReader as @internal: wrap it behind your own interface.
When it happens
Trigger: Calling AttributeReader::getPropertyAttributeCollection($property, $attribute) with a non-repeatable mapping attribute such as Column::class, JoinColumn::class, OneToMany::class, Embedded::class.
Common situations: Generic attribute-walking code that always calls the collection API for uniformity; refactoring from one getter to the other without checking the attribute's #[Attribute] flags; custom attributes missing the IS_REPEATABLE flag.
Related errors
- The attribute "%s" is repeatable. Call getPropertyAttributeC
- Undefined method "%s". The method name must start with eithe
- %s::$%s must be readonly property
- %s::$%s must have a type when used with TypedNoDefaultProper
- %s::$%s must not be nullable when used with TypedNoDefaultPr
AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21).
Data as JSON: /api/errors/30165836557dbc33.
Report an issue: GitHub.