phalcon/cphalcon · error · Phalcon\Annotations\Exceptions\CannotReadAnnotationData
Cannot read annotation data
Error message
Cannot read annotation data
What it means
The Annotations Stream adapter caches parsed annotations as serialized Reflection objects on disk. On read, unserialize() runs under a temporary error handler; if unserialize emits any E_WARNING (bad data, wrong offset, truncated payload), the handler sets a flag and the adapter throws CannotReadAnnotationData instead of returning garbage. It means the cache file under annotationsDir exists but its contents cannot be unserialized.
Source
Thrown at phalcon/Annotations/Adapter/Stream.zep:94
if unlikely empty contents {
return false;
}
globals_set("warning.enable", false);
set_error_handler(
function (number, message, file, line) {
globals_set("warning.enable", true);
},
E_WARNING
);
let contents = unserialize(contents);
restore_error_handler();
if unlikely globals_get("warning.enable") {
throw new CannotReadAnnotationData();
}
return contents;
}
/**
* Writes parsed annotations to files
*/
public function write( string key, <Reflection> data) -> void
{
var code;
string path;
/**
* Paths must be normalized before be used as keys
*/
let path = this->annotationsDir . prepare_virtual_path(key, "_") . ".php",
code = serialize(data);View on GitHub (pinned to b7419de9cd)
Solutions
- Delete everything under the configured annotationsDir so annotations are re-parsed and re-cached on the next request
- If it recurs, check the directory for concurrent writers and give each deployment its own cache prefix/directory
- Verify the annotationsDir is writable and not subject to open_basedir restrictions that could corrupt write behavior
- As a stopgap, switch to the Memory adapter (no disk cache) while you fix the underlying serialization issue
Example fix
// before: stale/corrupt cache triggers CannotReadAnnotationData on first get()
$annotations = new \Phalcon\Annotations\Adapter\Stream(['annotationsDir' => '/app/storage/annotations/']);
$reflector = $annotations->get(Invoices::class);
// after: purge the cache once after upgrading, then use normally
foreach (glob('/app/storage/annotations/*.php') ?: [] as $file) {
unlink($file);
}
$reflector = $annotations->get(Invoices::class); Defensive patterns
Strategy: fallback
Try / catch
try {
$reflector = $annotations->get(Invoices::class);
} catch (\Phalcon\Annotations\Exceptions\CannotReadAnnotationData $e) {
// cache entry corrupt: purge and regenerate once, then retry
array_map('unlink', glob($annotationsDir . '*.php') ?: []);
$reflector = $annotations->get(Invoices::class);
} Prevention
- Clear the annotations cache as part of every Phalcon/PHP upgrade deployment step
- Give each deployment its own cache directory to avoid cross-version file mixing
- Monitor disk-full events and concurrent writers on the cache directory
When it happens
Trigger: `$annotations->get($class)` / `$annotations->read($key)` on a class whose cached file in annotationsDir is corrupt or incompatible: truncated writes (disk full, killed process), cache files produced by an older Phalcon/PHP release, or files edited by hand.
Common situations: Deploying a new Phalcon version over old cache files; concurrent workers writing the same cache key; a disk-full event truncating serialized payloads; copying caches between environments built by different PHP versions.
Related errors
- Annotations directory cannot be written
- The expression {type} is unknown
- Collection does not have an annotation called '{name}'
- Stream adapter file does not exist: {path}
- Stream adapter cannot read file: {path}
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/55fd91b991b2de79.
Report an issue: GitHub.