{"record":{"id":"2cc32e200c95c960","repo":"doctrine/annotations","slug":"the-annotation-s-declared-on-s-does-not-have-a-property","errorCode":null,"errorMessage":"The annotation @%s declared on %s does not have a property named \"%s\"\nthat can be set through its named arguments constructor.\nAvailable named arguments: %s","messagePattern":"The annotation @(.+?) declared on (.+?) does not have a property named \"(.+?)\"\nthat can be set through its named arguments constructor\\.\nAvailable named arguments: (.+?)","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"lib/Doctrine/Common/Annotations/DocParser.php","lineNumber":941,"sourceCode":"                        }\n                    }\n                }\n            } elseif (gettype($values[$property]) !== $type['type'] && ! $values[$property] instanceof $type['type']) {\n                throw AnnotationException::attributeTypeError(\n                    $property,\n                    $originalName,\n                    $this->context,\n                    'a(n) ' . $type['value'],\n                    $values[$property]\n                );\n            }\n        }\n\n        if (self::$annotationMetadata[$name]['has_named_argument_constructor']) {\n            if (PHP_VERSION_ID >= 80000) {\n                foreach ($values as $property => $value) {\n                    if (! isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {\n                        throw AnnotationException::creationError(sprintf(\n                            <<<'EXCEPTION'\nThe annotation @%s declared on %s does not have a property named \"%s\"\nthat can be set through its named arguments constructor.\nAvailable named arguments: %s\nEXCEPTION\n                            ,\n                            $originalName,\n                            $this->context,\n                            $property,\n                            implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))\n                        ));\n                    }\n                }\n\n                return $this->instantiateAnnotiation($originalName, $this->context, $name, $values);\n            }\n\n            $positionalValues = [];","sourceCodeStart":923,"sourceCodeEnd":959,"githubUrl":"https://github.com/doctrine/annotations/blob/17815fb6b2f4c3c701ba2abdf2c6c97b219fb2e4/lib/Doctrine/Common/Annotations/DocParser.php#L923-L959","documentation":"Doctrine Annotations throws this when an annotation class uses a PHP 8 named-argument constructor (has_named_argument_constructor) and the DocParser encounters an attribute key in the annotation usage that is not a named parameter of the annotation's constructor. The parser validates each key in $values against the constructor's parameter list before instantiating, so an unknown key aborts annotation creation. The message lists the valid named arguments to help you spot the typo.","triggerScenarios":"Using an annotation like @Column(type=\"string\", nonexistent=\"x\") where the annotation class has a promoted-properties constructor and 'nonexistent' is not one of its constructor parameter names. Also triggered after upgrading an annotation class whose constructor signature changed (renamed/removed parameters) while call sites still use the old keys.","commonSituations":"Typos in annotation attribute names; migrating annotations to PHP 8 constructor promotion without updating usages; IDE autocomplete on a different annotation version than the one installed; copying annotation usage from documentation of a different library version.","solutions":["Fix the attribute name in the annotation usage to match one of the annotation class's constructor parameters (see 'Available named arguments' in the message).","Read the annotation class's constructor to confirm the exact parameter names and types.","If the annotation class is yours and the key is intentional, add the corresponding promoted constructor parameter.","Check the installed dependency version: the annotation class may differ from the version your docs assume; update usages or the dependency."],"exampleFix":"// before\n/** @Column(typ=\"string\", nullable=true) */\n// after\n/** @Column(type=\"string\", nullable=true) */","handlingStrategy":"validation","validationCode":"$ctor = (new ReflectionClass(MyAnnotation::class))->getConstructor();\n$allowed = $ctor ? array_map(fn($p) => $p->getName(), $ctor->getParameters()) : [];\n$used = ['type' => 'string', 'nmae' => 'x']; // keys from the docblock\n$unknown = array_diff(array_keys($used), $allowed);\nif ($unknown) {\n    throw new LogicException('Unknown annotation attributes: ' . implode(',', $unknown));\n}","typeGuard":"function isValidAnnotationAttribute(string $class, string $attr): bool {\n    $ctor = (new ReflectionClass($class))->getConstructor();\n    if ($ctor === null) return false;\n    foreach ($ctor->getParameters() as $p) {\n        if ($p->getName() === $attr) return true;\n    }\n    return false;\n}","tryCatchPattern":"try {\n    $parsed = $reader->getPropertyAnnotation($prop, MyAnnotation::class);\n} catch (AnnotationException $e) {\n    if (str_contains($e->getMessage(), 'does not have a property named')) {\n        // fall back to defaults or re-raise with file/line context\n    }\n    throw $e;\n}","preventionTips":["Keep docblock attributes in sync with the annotation class constructor after refactors.","Run annotation parsing in CI on all files to catch typos early.","Enable IDE annotation support (e.g. PhpStorm Doctrine plugin) for attribute autocomplete.","Pin annotation library versions and re-check usages when upgrading."],"tags":["php","doctrine-annotations","named-arguments","annotation-parsing"],"backgroundTag":"invalid-constructor-argument","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"}