doctrine/annotations · error · AnnotationException
The annotation @ declared on does not have a property named…
Error message
The annotation @%s declared on %s does not have a property named "%s". Available properties: %s
What it means
For annotations WITHOUT a named-argument constructor, DocParser instantiates the annotation and sets values via public properties. If a supplied attribute key is neither 'value' (the implicit default-property alias) nor a declared property in the annotation metadata, creation fails with this error listing available properties.
Solutions
- Rename the attribute to match an actual public property of the annotation class (see 'Available properties' in the message).
- Check the annotation class definition for the exact property names and visibility.
- If it is your own annotation, declare the missing public property.
- Verify you are annotating with the intended annotation class; remove attributes that belong to a different annotation.
Example fix
// before
/** @Table(name="users", indezes={@Index(name="idx", columns={"email"})}) */
// after
/** @Table(name="users", indexes={@Index(name="idx", columns={"email"})}) */ Defensive patterns
Strategy: validation
Validate before calling
$ref = new ReflectionClass(Entity::class);
$public = array_map(fn($p) => $p->getName(), $ref->getProperties(ReflectionProperty::IS_PUBLIC));
$used = ['readOnly' => true];
$unknown = array_diff(array_keys($used), array_merge($public, ['value']));
if ($unknown) {
throw new LogicException('Unknown @Entity attributes: ' . implode(',', $unknown));
} Type guard
function annotationHasProperty(string $class, string $prop): bool {
if ($prop === 'value') return true; // default-property alias path
try {
return (new ReflectionProperty($class, $prop))->isPublic();
} catch (ReflectionException) {
return false;
}
} Try / catch
try {
$meta = $reader->getClassAnnotation($class, Entity::class);
} catch (AnnotationException $e) {
if (str_contains($e->getMessage(), 'Available properties')) {
// fail fast with a clearer message pointing at the docblock
}
throw $e;
} Prevention
- Match exact property names/case from the annotation class source.
- Only set attributes that are public properties on non-constructor annotations.
- Validate docblocks in CI with a docblock lint pass.
- Re-read annotation class docs after library upgrades.
When it happens
Trigger: @Entity(readOnly=true) where 'readOnly' is not a public property of the Entity annotation class and the class has no named-argument constructor. Any unknown key other than 'value' triggers it, even if the annotation has no properties at all.
Common situations: Setting attributes on annotations that only expose constants or methods; typos in property names; assuming camelCase when the property is snake_case (or vice versa); using attributes from a different annotation class by mistake.
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
- The annotation @ declared on does not have a property named…
- The annotation @ declared on does not accept any values…
- Couldn't find constant
- An error occurred while instantiating the annotation @
AI-assisted analysis of doctrine/annotations@17815fb6b2 (2026-09-15).
Data as JSON: /api/errors/aa4586577f75e97f.
Report an issue: GitHub.
Appendix: source
Thrown at lib/Doctrine/Common/Annotations/DocParser.php:997
$positionalValues[self::$annotationMetadata[$name]['constructor_args'][$property]['position']] = $value;
}
return $this->instantiateAnnotiation($originalName, $this->context, $name, $positionalValues);
}
// check if the annotation expects values via the constructor,
// or directly injected into public properties
if (self::$annotationMetadata[$name]['has_constructor'] === true) {
return $this->instantiateAnnotiation($originalName, $this->context, $name, [$values]);
}
$instance = $this->instantiateAnnotiation($originalName, $this->context, $name, []);
foreach ($values as $property => $value) {
if (! isset(self::$annotationMetadata[$name]['properties'][$property])) {
if ($property !== 'value') {
throw AnnotationException::creationError(sprintf(
<<<'EXCEPTION'
The annotation @%s declared on %s does not have a property named "%s".
Available properties: %s
EXCEPTION
,
$originalName,
$this->context,
$property,
implode(', ', self::$annotationMetadata[$name]['properties'])
));
}
// handle the case if the property has no annotations
$property = self::$annotationMetadata[$name]['default_property'];
if (! $property) {
throw AnnotationException::creationError(sprintf(
'The annotation @%s declared on %s does not accept any values, but got %s.',
$originalName,View on GitHub (pinned to 17815fb6b2)