getgrav/grav · error · RuntimeException
500
500
Error message
Internal Error
What it means
During Install::prepare(), Grav resolves its own installer directory with `realpath(__DIR__)`; if that returns false it throws RuntimeException 500 'Internal Error'. realpath() fails when the path cannot be resolved at all — the directory was deleted or replaced mid-run, a symlink loop exists, or a path component lost permissions. It is a defensive environment sanity check and is exceptionally rare.
Source
Thrown at system/src/Grav/Installer/Install.php:308
$this->checkVersion($results, 'grav', 'grav', $this->requires['grav'], GRAV_VERSION);
$this->checkPlugins($results, $this->requires['plugins']);
return $results;
}
/**
* @return void
* @throws RuntimeException
*/
public function prepare(): void
{
// Locate the new Grav update and the target site from the filesystem.
$this->ensureLocation();
$location = realpath(__DIR__);
$target = realpath(GRAV_ROOT . '/index.php');
if (!$location) {
throw new RuntimeException('Internal Error', 500);
}
if ($target && dirname($location, 4) === dirname($target)) {
// We cannot copy files into themselves, abort!
throw new RuntimeException('Grav has already been installed here!', 400);
}
// Load the installer classes.
foreach ($this->classMap as $class_name => $path) {
// Make sure that none of the Grav\Installer classes have been loaded, otherwise installation may fail!
if (class_exists($class_name, false)) {
throw new RuntimeException(sprintf('Cannot update Grav, class %s has already been loaded!', $class_name), 500);
}
require $path;
}
$this->legacySupport();View on GitHub (pinned to 6040efed04)
Solutions
- Re-run direct-install from a stable, fully-present codebase — the previous attempt was racing a deploy or the tree was incomplete
- Check the deployment layout for dangling/looping symlinks around GRAV_ROOT and system/
- Verify directory permissions on every path component of the installer directory
Defensive patterns
Strategy: validation
Validate before calling
// Sanity-check the codebase before invoking the installer
$installerDir = realpath(GRAV_ROOT . '/system/src/Grav/Installer');
if ($installerDir === false || !is_dir($installerDir) || !is_readable($installerDir)) {
throw new \RuntimeException('Installer directory missing or unreadable — codebase incomplete');
} Prevention
- Do not run direct-install concurrently with deploys that replace the codebase
- Verify release symlinks resolve to existing directories before upgrading
- Treat this as an environment integrity signal: re-run from a verified-complete checkout
When it happens
Trigger: The system/src/Grav/Installer directory being deleted, moved, or having its symlink chain broken while direct-install runs; a symlink loop in the deployment layout; permissions revoked on a parent directory between process start and the realpath call.
Common situations: Deploys that rsync-delete the codebase concurrently with an upgrade; broken symlink-based release directories (capistrano-style layouts pointing at a removed release).
Related errors
- Invalid backup location: {$backup_root}
- 400
- Backup location: {$backup_root} does not exist...
- Unable to %s: %s
- Unknown error
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/f5b5f807db4b60ec.
Report an issue: GitHub.