doctrine/annotations · error · AnnotationException
Couldn't find constant
Error message
Couldn't find constant %s%s.
What it means
DocParser resolves PHP constants referenced inside annotation values (e.g. @Annotation(MyClass::STATUS)). When the parsed identifier is not a defined constant (defined() returns false), AnnotationException::semanticalErrorConstants throws "Couldn't find constant %s" including the annotation context. This guards against silently passing an undefined constant name, which plain PHP would only warn about and cast to a string.
Solutions
- Verify the constant exists and its name/case matches: check the defining class or define() call.
- Add the correct use import so the identifier resolves to the right class, or use the fully qualified class name in the annotation.
- Ensure the file defining the constant is autoloaded/required before the annotation is parsed (check bootstrap order).
- If referencing an enum case, upgrade doctrine/annotations and PHP to versions that support enums, or use a plain scalar instead.
Example fix
// before /** @Column(type=Types::STRNG) */ // after use Doctrine\DBAL\Types; /** @Column(type=Types::STRING) */
Defensive patterns
Strategy: try-catch
Validate before calling
if (!class_exists(MyClass::class)) {
throw new LogicException('Class used in annotation not autoloadable');
}
if (!defined('MyClass::STATUS') && !defined('STATUS')) {
throw new LogicException('Constant referenced in annotation does not exist');
} Try / catch
try {
$annot = $reader->getClassAnnotation($class, MyAnnotation::class);
} catch (AnnotationException $e) {
if (str_contains($e->getMessage(), "Couldn't find constant")) {
$defaultValue = 'fallback'; // or re-raise with more context
} else {
throw $e;
}
} Prevention
- Always import classes used in annotations with use statements.
- Never reference constants defined conditionally after parsing begins.
- Avoid using enum cases in annotations with older doctrine/annotations; use scalars.
- Verify '::' references in docblocks in CI with a static checker (e.g. PHPStan doctrine extension).
When it happens
Trigger: Referencing Class::CONSTANT or FQCN\CONSTANT in an annotation where the class or constant does not exist or is not autoloadable; using an undefined global constant in an annotation value; referencing an enum case on PHP < 8.1 or an older doctrine/annotations version; typo in the constant name.
Common situations: Refactoring that renamed or removed a class constant while annotations still reference the old name; missing use imports so the identifier resolves to the wrong FQCN; constants defined conditionally via define() in bootstrap code not yet executed.
Related errors
- The annotation @ declared on does not have a property named…
- The annotation @ declared on does not have a property named…
- The annotation @ declared on does not accept any values…
- An error occurred while instantiating the annotation @
AI-assisted analysis of doctrine/annotations@17815fb6b2 (2026-09-15).
Data as JSON: /api/errors/088b90bde6baf3a2.
Report an issue: GitHub.
Appendix: source
Thrown at lib/Doctrine/Common/Annotations/DocParser.php:1164
}
}
/**
* Checks if identifier ends with ::class and remove the leading backslash if it exists.
*/
if (
$this->identifierEndsWithClassConstant($identifier) &&
! $this->identifierStartsWithBackslash($identifier)
) {
return substr($identifier, 0, $this->getClassConstantPositionInIdentifier($identifier));
}
if ($this->identifierEndsWithClassConstant($identifier) && $this->identifierStartsWithBackslash($identifier)) {
return substr($identifier, 1, $this->getClassConstantPositionInIdentifier($identifier) - 1);
}
if (! defined($identifier)) {
throw AnnotationException::semanticalErrorConstants($identifier, $this->context);
}
return constant($identifier);
}
private function identifierStartsWithBackslash(string $identifier): bool
{
return $identifier[0] === '\\';
}
private function identifierEndsWithClassConstant(string $identifier): bool
{
return $this->getClassConstantPositionInIdentifier($identifier) === strlen($identifier) - strlen('::class');
}
/** @return int|false */
private function getClassConstantPositionInIdentifier(string $identifier)
{View on GitHub (pinned to 17815fb6b2)