{"record":{"id":"aa4586577f75e97f","repo":"doctrine/annotations","slug":"the-annotation-s-declared-on-s-does-not-have-a-property-aa4586","errorCode":null,"errorMessage":"The annotation @%s declared on %s does not have a property named \"%s\".\nAvailable properties: %s","messagePattern":"The annotation @(.+?) declared on (.+?) does not have a property named \"(.+?)\"\\.\nAvailable properties: (.+?)","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"lib/Doctrine/Common/Annotations/DocParser.php","lineNumber":997,"sourceCode":"\n                $positionalValues[self::$annotationMetadata[$name]['constructor_args'][$property]['position']] = $value;\n            }\n\n            return $this->instantiateAnnotiation($originalName, $this->context, $name, $positionalValues);\n        }\n\n        // check if the annotation expects values via the constructor,\n        // or directly injected into public properties\n        if (self::$annotationMetadata[$name]['has_constructor'] === true) {\n            return $this->instantiateAnnotiation($originalName, $this->context, $name, [$values]);\n        }\n\n        $instance = $this->instantiateAnnotiation($originalName, $this->context, $name, []);\n\n        foreach ($values as $property => $value) {\n            if (! isset(self::$annotationMetadata[$name]['properties'][$property])) {\n                if ($property !== 'value') {\n                    throw AnnotationException::creationError(sprintf(\n                        <<<'EXCEPTION'\nThe annotation @%s declared on %s does not have a property named \"%s\".\nAvailable properties: %s\nEXCEPTION\n                        ,\n                        $originalName,\n                        $this->context,\n                        $property,\n                        implode(', ', self::$annotationMetadata[$name]['properties'])\n                    ));\n                }\n\n                // handle the case if the property has no annotations\n                $property = self::$annotationMetadata[$name]['default_property'];\n                if (! $property) {\n                    throw AnnotationException::creationError(sprintf(\n                        'The annotation @%s declared on %s does not accept any values, but got %s.',\n                        $originalName,","sourceCodeStart":979,"sourceCodeEnd":1015,"githubUrl":"https://github.com/doctrine/annotations/blob/17815fb6b2f4c3c701ba2abdf2c6c97b219fb2e4/lib/Doctrine/Common/Annotations/DocParser.php#L979-L1015","documentation":"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.","triggerScenarios":"@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.","commonSituations":"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.","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."],"exampleFix":"// before\n/** @Table(name=\"users\", indezes={@Index(name=\"idx\", columns={\"email\"})}) */\n// after\n/** @Table(name=\"users\", indexes={@Index(name=\"idx\", columns={\"email\"})}) */","handlingStrategy":"validation","validationCode":"$ref = new ReflectionClass(Entity::class);\n$public = array_map(fn($p) => $p->getName(), $ref->getProperties(ReflectionProperty::IS_PUBLIC));\n$used = ['readOnly' => true];\n$unknown = array_diff(array_keys($used), array_merge($public, ['value']));\nif ($unknown) {\n    throw new LogicException('Unknown @Entity attributes: ' . implode(',', $unknown));\n}","typeGuard":"function annotationHasProperty(string $class, string $prop): bool {\n    if ($prop === 'value') return true; // default-property alias path\n    try {\n        return (new ReflectionProperty($class, $prop))->isPublic();\n    } catch (ReflectionException) {\n        return false;\n    }\n}","tryCatchPattern":"try {\n    $meta = $reader->getClassAnnotation($class, Entity::class);\n} catch (AnnotationException $e) {\n    if (str_contains($e->getMessage(), 'Available properties')) {\n        // fail fast with a clearer message pointing at the docblock\n    }\n    throw $e;\n}","preventionTips":["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."],"tags":["php","doctrine-annotations","annotation-properties","annotation-parsing"],"backgroundTag":"invalid-argument-value","analyzedSha":"17815fb6b2f4c3c701ba2abdf2c6c97b219fb2e4","analyzedAt":"2026-09-15T20:30:41.547Z","contentChangedAt":"2026-09-15T20:30:41.547Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}