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

  1. Rename the attribute to match an actual public property of the annotation class (see 'Available properties' in the message).
  2. Check the annotation class definition for the exact property names and visibility.
  3. If it is your own annotation, declare the missing public property.
  4. 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

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


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)