{"record":{"id":"c09ebb007f28066e","repo":"getgrav/grav","slug":"creating-directory-failed-for-filepath","errorCode":null,"errorMessage":"Creating directory failed for {filepath}","messagePattern":"Creating directory failed for (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/File/AbstractFile.php","lineNumber":191,"sourceCode":"\n    /**\n     * {@inheritdoc}\n     * @see FileInterface::getModificationTime()\n     */\n    public function getModificationTime(): int\n    {\n        return is_file($this->filepath) ? (int)filemtime($this->filepath) : time();\n    }\n\n    /**\n     * {@inheritdoc}\n     * @see FileInterface::lock()\n     */\n    public function lock(bool $block = true): bool\n    {\n        if (!$this->handle) {\n            if (!$this->mkdir($this->getPath())) {\n                throw new RuntimeException('Creating directory failed for ' . $this->filepath);\n            }\n            $this->handle = @fopen($this->filepath, 'cb+') ?: null;\n            if (!$this->handle) {\n                $error = error_get_last();\n                $message = $error['message'] ?? 'Unknown error';\n\n                throw new RuntimeException(\"Opening file for writing failed on error {$message}\");\n            }\n        }\n\n        $lock = $block ? LOCK_EX : LOCK_EX | LOCK_NB;\n\n        // Some filesystems do not support file locks, only fail if another process holds the lock.\n        $this->locked = flock($this->handle, $lock, $wouldBlock) || !$wouldBlock;\n\n        return $this->locked;\n    }\n","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/File/AbstractFile.php#L173-L209","documentation":"AbstractFile::lock() needs a write handle, so before @fopen it guarantees the file's parent directory exists via mkdir(); when that returns false it throws this RuntimeException with the file path embedded. It is an environment failure, not a data problem: the PHP process cannot create the directory — permissions, open_basedir, a read-only filesystem, or a path component that is a regular file.","triggerScenarios":"Calling lock() on a File whose directory does not exist and cannot be created: parent directory not writable by the web-server/PHP-FPM user; path outside open_basedir; read-only mount; a parent path segment exists as a file rather than a directory.","commonSituations":"Fresh deploy where storage directories were created by root during upload and never chowned; shared hosting with open_basedir restrictions; containers with read-only volumes; SELinux/AppArmor denials after a server migration.","solutions":["Fix ownership and permissions on every parent directory so the PHP user can write: chown -R www-data:www-data <dir> && chmod -R 775 <dir>.","Create the directory manually (mkdir -p) and verify the PHP user can write a test file into it.","Check open_basedir (php -i / admin panel) covers the path and the mount is not read-only.","Standardize on a single PHP user for CLI and web so directory ownership never flips."],"exampleFix":"# before: RuntimeException \"Creating directory failed for /var/www/grav/user/data/plugin/x.json\"\nls -ld /var/www/grav/user/data        # owned by root:root\nsudo chown -R www-data:www-data /var/www/grav/user/data\nsudo chmod -R 775 /var/www/grav/user/data\n# after: lock() creates the directory and opens the handle","handlingStrategy":"validation","validationCode":"$dir = dirname($filepath);\nif (!is_dir($dir) && !is_writable(dirname($dir))) {\n    // mkdir inside lock() will fail: fix permissions or choose another path\n}","typeGuard":null,"tryCatchPattern":"try {\n    $file->lock();\n} catch (\\RuntimeException $e) {\n    // filesystem/environment problem: surface to admin, do not retry blindly\n    $alerts->notify('Cannot lock ' . $file->getFilePath() . ': ' . $e->getMessage());\n}","preventionTips":["Provision storage directories (with correct ownership) as part of deployment, not lazily at runtime.","Run web and CLI PHP under the same user to keep directory ownership consistent.","Monitor free space and mount states; read-only mounts turn into this error immediately."],"tags":["php","grav","filesystem","permissions","mkdir"],"backgroundTag":"directory-permission-denied","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}