{"record":{"id":"e8ecf9e4e577acfa","repo":"phalcon/cphalcon","slug":"annotations-directory-cannot-be-written","errorCode":null,"errorMessage":"Annotations directory cannot be written","messagePattern":"Annotations directory cannot be written","errorType":"exception","errorClass":"Phalcon\\Annotations\\Exceptions\\AnnotationsDirectoryNotWritable","httpStatus":null,"severity":"error","filePath":"phalcon/Annotations/Adapter/Stream.zep","lineNumber":115,"sourceCode":"        return contents;\n    }\n\n    /**\n     * Writes parsed annotations to files\n     */\n    public function write( string key, <Reflection> data) -> void\n    {\n        var code;\n        string path;\n\n        /**\n         * Paths must be normalized before be used as keys\n         */\n        let path = this->annotationsDir . prepare_virtual_path(key, \"_\") . \".php\",\n            code = serialize(data);\n\n        if unlikely this->phpFilePutContents(path, code) === false {\n            throw new AnnotationsDirectoryNotWritable();\n        }\n    }\n}\n","sourceCodeStart":97,"sourceCodeEnd":119,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Annotations/Adapter/Stream.zep#L97-L119","documentation":"When the Annotations Stream adapter wants to persist a parsed Reflection it writes a serialized blob via file_put_contents into annotationsDir. If that call returns false the adapter throws AnnotationsDirectoryNotWritable. The usual cause is that the cache directory does not exist or the PHP process user lacks write permission on it.","triggerScenarios":"First `$annotations->get($class)` (cache miss triggers write) where annotationsDir is missing, read-only for the web-server user, blocked by open_basedir, or the disk is full.","commonSituations":"Deployment forgot to create storage/cache/annotations; directory owned by root while php-fpm runs as www-data; read-only container filesystem; safe_mode/open_basedir restrictions in shared hosting.","solutions":["Create the directory: `mkdir -p /app/storage/annotations`","Grant write access to the PHP user: `chown -R www-data:www-data /app/storage/annotations` or `chmod 775` plus group membership","Check open_basedir includes the directory and the volume is not full (`df -h`)","On read-only filesystems (containers) mount a writable volume for the cache or use the Memory adapter"],"exampleFix":"// before\n$di->set('annotations', function () {\n    return new \\Phalcon\\Annotations\\Adapter\\Stream(['annotationsDir' => '/app/storage/annotations/']);\n});\n// after: fail fast at boot instead of mid-request\n$dir = '/app/storage/annotations/';\nif (!is_dir($dir)) {\n    mkdir($dir, 0775, true);\n}\nif (!is_writable($dir)) {\n    throw new RuntimeException('Annotations directory not writable: ' . $dir);\n}","handlingStrategy":"validation","validationCode":"$dir = rtrim($options['annotationsDir'] ?? '', '/') . '/';\nif (!is_dir($dir)) {\n    mkdir($dir, 0775, true);\n}\nif (!is_writable($dir)) {\n    throw new RuntimeException('Annotations cache dir not writable: ' . $dir);\n}\n$adapter = new \\Phalcon\\Annotations\\Adapter\\Stream(['annotationsDir' => $dir]);","typeGuard":null,"tryCatchPattern":"try {\n    $reflector = $annotations->get(Invoices::class);\n} catch (\\Phalcon\\Annotations\\Exceptions\\AnnotationsDirectoryNotWritable $e) {\n    // surface as a deployment/infrastructure alert, not a 500 to the user\n    $logger->error('Annotation cache unwritable: ' . $e->getMessage());\n    throw $e;\n}","preventionTips":["Create and chmod cache directories in the deployment script, not at runtime","Run a boot-time is_dir()/is_writable() health check on all configured cache directories","In containers, mount a writable volume for cache paths"],"tags":["annotations","cache","permissions","filesystem"],"backgroundTag":"directory-not-writable","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}