getgrav/grav · warning · RuntimeException

Unknown error

Error message

Unknown error

What it means

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.

Source

Thrown at system/src/Grav/Common/Filesystem/Folder.php:435

    {
        if (!is_dir($target)) {
            return false;
        }

        $failure = null;
        $success = self::doDelete($target, $include_target, $failure);

        if (!$success) {
            // Prefer the precise reason captured at the first failing path
            // (which file/dir, the OS error, and any owner/process mismatch).
            // Fall back to the last PHP error, then to a generic message.
            if (null !== $failure) {
                throw new RuntimeException($failure);
            }

            $error = error_get_last();

            throw new RuntimeException($error['message'] ?? 'Unknown error');
        }

        // Make sure that the change will be detected when caching.
        if ($include_target) {
            @touch(dirname($target));
        } else {
            @touch($target);
        }

        return $success;
    }

    /**
     * @param  string  $folder
     * @return void
     * @throws RuntimeException
     */
    public static function mkdir($folder)

View on GitHub (pinned to 6040efed04)

Solutions

  1. Re-run the deletion immediately — transient races (concurrent purge of the same tree) often clear themselves
  2. Manually inspect the target path: ls -la, file owner, mount type (mount | grep <path>) to spot vanishing or foreign-mount directories
  3. 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
  4. If the tree is on NFS/FUSE/samba, test deleting one file by hand as the same user to reproduce the underlying OS error
Defensive patterns

Strategy: retry

Try / catch

try {
    Folder::delete($dir);
} catch (RuntimeException $e) {
    if ($e->getMessage() === 'Unknown error') {
        // diagnostics were suppressed — one immediate retry covers races; then investigate manually
        Folder::delete($dir);
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/8c302b2b2ec6ff3d. Report an issue: GitHub.