{"record":{"id":"dad836f84a21026f","repo":"phalcon/cphalcon","slug":"no-annotations-were-found-in-class-classname","errorCode":null,"errorMessage":"No annotations were found in class {className}","messagePattern":"No annotations were found in class (.+?)","errorType":"exception","errorClass":"Phalcon\\Mvc\\Model\\MetaData\\Exceptions\\NoAnnotationsForClass","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Model/MetaData/Strategy/Annotations.zep","lineNumber":43,"sourceCode":"     */\n    final public function getColumnMaps(<ModelInterface> model, <DiInterface> container) -> array\n    {\n        var annotations, className, reflection, propertiesAnnotations, property,\n            propAnnotations, columnAnnotation, columnName;\n        array orderedColumnMap, reversedColumnMap;\n        bool hasReversedColumn;\n\n        if unlikely typeof container != \"object\" {\n            throw new InvalidContainer();\n        }\n\n        let annotations = container->get(\"annotations\");\n\n        let className = get_class(model),\n            reflection = annotations->get(className);\n\n        if unlikely typeof reflection != \"object\" {\n            throw new NoAnnotationsForClass(className);\n        }\n\n        /**\n         * Get the properties defined in\n         */\n        let propertiesAnnotations = reflection->getPropertiesAnnotations();\n\n        if unlikely empty propertiesAnnotations {\n            throw new NoPropertyAnnotationsForClass(className);\n        }\n\n        let orderedColumnMap = [],\n            reversedColumnMap = [],\n            hasReversedColumn = false;\n\n        for property, propAnnotations in propertiesAnnotations {\n            /**\n             * All columns marked with the 'Column' annotation are considered columns","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Model/MetaData/Strategy/Annotations.zep#L25-L61","documentation":"When the Annotations metadata strategy builds column maps, it asks the 'annotations' service for a Reflection of the model class ($annotations->get($className)) and requires an object back. If the service returns anything non-object — typically a cached annotation entry that deserialized into a scalar (serializer mismatch, entry written by another version) or a custom annotations adapter whose read() returns junk — this exception is thrown with the class name. Note the distinction: a class with no annotations normally yields an empty Reflection and fails later with NoPropertyAnnotationsForClass; this error means no Reflection object came back at all.","triggerScenarios":"Running the Annotations strategy (or custom code calling Annotations::getColumnMaps()) on a model whose class-name key in the annotations cache holds a non-object value; a custom 'annotations' service whose get() can return null/scalars; an annotations backend shared across servers with different serializers or Phalcon versions.","commonSituations":"Switching annotations adapters (APCu to Redis) while old entries persist under the same class keys; igbinary/serialize mismatch after a PHP or Phalcon upgrade; home-grown annotations adapters that skip parsing and return null on misses.","solutions":["Flush the annotations cache backend (delete the class keys / clear APCu) so entries are re-parsed from source.","Verify the 'annotations' DI service resolves to a standard Phalcon annotations adapter and that its serializer matches on every server.","If the model genuinely has no annotations, switch the metadata strategy to Introspection (the default) or annotate the model properties (@Column, @Primary, @Identity).","After serializer or version changes, change the annotations cache prefix so old and new entries never mix."],"exampleFix":"// before: annotations cache poisoned by a serializer change\n$di->setShared('annotations', function () {\n    return new Phalcon\\Annotations\\Adapter\\Redis(['prefix' => 'annotations']);\n});\n$strategy->getColumnMaps(new Invoices(), $di); // NoAnnotationsForClass\n\n// after: bump the prefix (or flush) after serializer/version changes\n$di->setShared('annotations', function () {\n    return new Phalcon\\Annotations\\Adapter\\Redis(['prefix' => 'annotations-v2']);\n});","handlingStrategy":"validation","validationCode":"$annotations = $container->getShared('annotations');\nif (!is_object($annotations->get(Invoices::class))) {\n    throw new RuntimeException('Stale annotations cache for ' . Invoices::class . ' - flush the backend');\n}","typeGuard":"function annotationsReflectionIsObject(object $annotations, string $className): bool\n{\n    return is_object($annotations->get($className));\n}","tryCatchPattern":"use Phalcon\\Mvc\\Model\\MetaData\\Exceptions\\NoAnnotationsForClass;\n\ntry {\n    $maps = $strategy->getColumnMaps($model, $container);\n} catch (NoAnnotationsForClass $e) {\n    flushAnnotationsBackend(); // delete class-keyed entries\n    $maps = $strategy->getColumnMaps($model, $container); // re-parse once\n}","preventionTips":["Version the annotations cache prefix whenever PHP, Phalcon, or the serializer changes.","Use the same serializer configuration on every node sharing an annotations backend.","Prefer the Introspection strategy unless the codebase actually uses model annotations."],"tags":["phalcon","orm","annotations","metadata","cache-corruption"],"backgroundTag":"missing-class-annotations","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}