{"record":{"id":"8c302b2b2ec6ff3d","repo":"getgrav/grav","slug":"unknown-error","errorCode":null,"errorMessage":"Unknown error","messagePattern":"Unknown error","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"warning","filePath":"system/src/Grav/Common/Filesystem/Folder.php","lineNumber":435,"sourceCode":"    {\n        if (!is_dir($target)) {\n            return false;\n        }\n\n        $failure = null;\n        $success = self::doDelete($target, $include_target, $failure);\n\n        if (!$success) {\n            // Prefer the precise reason captured at the first failing path\n            // (which file/dir, the OS error, and any owner/process mismatch).\n            // Fall back to the last PHP error, then to a generic message.\n            if (null !== $failure) {\n                throw new RuntimeException($failure);\n            }\n\n            $error = error_get_last();\n\n            throw new RuntimeException($error['message'] ?? 'Unknown error');\n        }\n\n        // Make sure that the change will be detected when caching.\n        if ($include_target) {\n            @touch(dirname($target));\n        } else {\n            @touch($target);\n        }\n\n        return $success;\n    }\n\n    /**\n     * @param  string  $folder\n     * @return void\n     * @throws RuntimeException\n     */\n    public static function mkdir($folder)","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Common/Filesystem/Folder.php#L417-L453","documentation":"Folder::delete() falls back to error_get_last() when doDelete() fails without capturing a specific path failure; if PHP recorded no error either, you get the terminal RuntimeException 'Unknown error'. It means recursive deletion returned false from operations whose diagnostics were fully suppressed — the informative paths of error [10] were exhausted. It is rare and usually accompanies exotic filesystem states where even the fallback has nothing to report.","triggerScenarios":"scandir() failing on a directory that vanished mid-iteration; suppressed unlink/rmdir failures that did not populate error_get_last() (errors captured by earlier handlers); filesystems with unusual failure modes (FUSE mounts, sandboxed containers); race conditions where another process removes files during the recursive walk.","commonSituations":"Two concurrent requests purging the same cache directory; mounted network storage with intermittent failures; opcache/anti-virus intercepting unlinks on Windows; container filesystem overlays with permission quirks.","solutions":["Re-run the deletion immediately — transient races (concurrent purge of the same tree) often clear themselves","Manually inspect the target path: ls -la, file owner, mount type (mount | grep <path>) to spot vanishing or foreign-mount directories","Instrument around the call: enable PHP error logging to file (log_errors=On, error_log set) so suppressed warnings are captured even when error_get_last() is empty","If the tree is on NFS/FUSE/samba, test deleting one file by hand as the same user to reproduce the underlying OS error"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    Folder::delete($dir);\n} catch (RuntimeException $e) {\n    if ($e->getMessage() === 'Unknown error') {\n        // diagnostics were suppressed — one immediate retry covers races; then investigate manually\n        Folder::delete($dir);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Enable PHP error logging (log_errors, error_log) so suppressed warnings are on disk even when error_get_last() is empty","Avoid concurrent purges of the same directory (stagger cron jobs)","Treat repeat 'Unknown error' as an environment smell — test manual deletion on the exact path as the same user"],"tags":["php","filesystem","file-deletion","unknown-error","race-condition"],"backgroundTag":"file-delete-failed","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}