{"record":{"id":"c59876f00b126271","repo":"getgrav/grav","slug":"unable-to-create-directory-s","errorCode":null,"errorMessage":"Unable to create directory: %s","messagePattern":"Unable to create directory: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Common/Filesystem/Folder.php","lineNumber":476,"sourceCode":"    /**\n     * @param  string  $folder\n     * @return void\n     * @throws RuntimeException\n     */\n    public static function create($folder)\n    {\n        // Silence error for open_basedir; should fail in mkdir instead.\n        if (@is_dir($folder)) {\n            return;\n        }\n\n        $success = @mkdir($folder, 0777, true);\n\n        if (!$success) {\n            // Take yet another look, make sure that the folder doesn't exist.\n            clearstatcache(true, $folder);\n            if (!@is_dir($folder)) {\n                throw new RuntimeException(sprintf('Unable to create directory: %s', $folder));\n            }\n        }\n    }\n\n    /**\n     * Recursive copy of one directory to another\n     *\n     * @param string $src\n     * @param string $dest\n     * @return bool\n     * @throws RuntimeException\n     */\n    public static function rcopy($src, $dest, $preservePermissions = false)\n    {\n\n        // If the src is not a directory do a simple file copy\n        if (!is_dir($src)) {\n            copy($src, $dest);","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Common/Filesystem/Folder.php#L458-L494","documentation":"Folder::create() (alias mkdir) wraps PHP mkdir($folder, 0777, true); if the recursive creation fails and a re-check (with clearstatcache) still shows no directory, it throws RuntimeException 'Unable to create directory: /path'. The double-check exists because mkdir can report failure while the directory actually exists (race); the throw therefore means the directory genuinely could not be created — permissions, open_basedir, path collision with an existing file, or disk exhaustion.","triggerScenarios":"Parent directory not writable by the PHP user (cache/, user/ under www-data while PHP runs as another UID); open_basedir excluding an ancestor of $folder; a regular file already exists at the exact $folder path; disk full or inode exhaustion; read-only filesystem mounts.","commonSituations":"Fresh installs where storage/ or cache/ were not chowned to the web user; hardening php.ini tightening open_basedir after the site worked; deploying with a Docker volume mounted read-only; permission-fix scripts that created files where directories were expected.","solutions":["Check write permission on the deepest existing ancestor: ls -ld $(dirname $folder) and compare with the PHP process user (whoami / posix_geteuid)","chown/chmod the parent chain so the web user can create children (e.g. chown -R www-data cache/ && chmod 755 cache/)","Verify open_basedir covers every path segment: php -i | grep open_basedir","Confirm nothing occupies the path as a file (ls -la $folder) and that the volume is not read-only/full (df -h, df -i)"],"exampleFix":"// before\nFolder::create(GRAV_ROOT . '/cache/compiled/pages'); // may throw blind\n\n// after — fail with context before calling\nuse Grav\\Common\\Filesystem\\Folder;\n\n$dir = GRAV_ROOT . '/cache/compiled/pages';\n$parent = dirname($dir);\nif (!is_dir($dir) && !is_writable($parent)) {\n    throw new RuntimeException(sprintf('Cannot create %s: parent %s not writable by UID %d', $dir, $parent, posix_geteuid()));\n}\nFolder::create($dir);","handlingStrategy":"validation","validationCode":"if (!is_dir($folder)) {\n    $parent = dirname($folder);\n    if (!is_dir($parent) || !is_writable($parent)) {\n        throw new RuntimeException(sprintf('%s is not writable by UID %d — cannot create %s', $parent, posix_geteuid(), $folder));\n    }\n}\nFolder::create($folder);","typeGuard":null,"tryCatchPattern":"try {\n    Folder::create($folder);\n} catch (RuntimeException $e) {\n    // check open_basedir, existing file at $folder, disk space, parent perms\n    $log->error($e->getMessage());\n    throw;\n}","preventionTips":["Verify is_writable() on the parent before deep creates; open_basedir failures are silent until mkdir","Ensure no regular file shadows the intended directory path","Include writable-directory assertions in deployment smoke tests (cache/, user/pages write checks)"],"tags":["php","filesystem","mkdir","permissions","open-basedir"],"backgroundTag":"directory-creation-failed","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}