{"record":{"id":"8d0ef18cb9b5f56e","repo":"getgrav/grav","slug":"400-8d0ef1","errorCode":"400","errorMessage":"Grav has already been installed here!","messagePattern":"Grav has already been installed here!","errorType":"http","errorClass":"RuntimeException","httpStatus":400,"severity":"error","filePath":"system/src/Grav/Installer/Install.php","lineNumber":313,"sourceCode":"\n    /**\n     * @return void\n     * @throws RuntimeException\n     */\n    public function prepare(): void\n    {\n        // Locate the new Grav update and the target site from the filesystem.\n        $this->ensureLocation();\n        $location = realpath(__DIR__);\n        $target = realpath(GRAV_ROOT . '/index.php');\n\n        if (!$location) {\n            throw new RuntimeException('Internal Error', 500);\n        }\n\n        if ($target && dirname($location, 4) === dirname($target)) {\n            // We cannot copy files into themselves, abort!\n            throw new RuntimeException('Grav has already been installed here!', 400);\n        }\n\n        // Load the installer classes.\n        foreach ($this->classMap as $class_name => $path) {\n            // Make sure that none of the Grav\\Installer classes have been loaded, otherwise installation may fail!\n            if (class_exists($class_name, false)) {\n                throw new RuntimeException(sprintf('Cannot update Grav, class %s has already been loaded!', $class_name), 500);\n            }\n\n            require $path;\n        }\n\n        $this->legacySupport();\n\n        $this->location = dirname($location, 4);\n\n        $versions = Versions::instance(USER_DIR . 'config/versions.yaml');\n        $this->updater = new VersionUpdater('core/grav', __DIR__ . '/updates', $this->getVersion(), $versions);","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Installer/Install.php#L295-L331","documentation":"Install::prepare() compares the directory of the update package's installer with the directory of the live index.php: if they are the same, copying would overwrite the package into itself, so it aborts with RuntimeException 400 'Grav has already been installed here!'. It means the updater found its own files sitting in the target site root — typically because an update zip was extracted into the live Grav root.","triggerScenarios":"Unzipping a grav-update package directly into GRAV_ROOT and then running direct-install on/inside it; pointing direct-install at a folder that is the live site itself; running the installer from a copy of Grav that shares the target root.","commonSituations":"Manually extracting the update to 'just look at it' in the webroot, then upgrading; confusing the download location with the install source in shell history.","solutions":["Keep the downloaded update zip outside the Grav root (e.g. tmp/) and install from it: `bin/gpm direct-install tmp/grav-update.zip`","If the package was already extracted into the webroot, remove that extracted copy (system/, vendor/, etc. that came from the zip) or restore from backup, then run direct-install from the zip"],"exampleFix":"# before\ncd /var/www/grav && unzip ~/grav-update-v1.8.0.zip -d . && bin/gpm direct-install . # self-copy -> 400\n\n# after\nbin/gpm direct-install /tmp/grav-update-v1.8.0.zip # install from the zip outside GRAV_ROOT","handlingStrategy":"validation","validationCode":"// Ensure the update source and the live site are not the same directory\n$updateDir = realpath($updateZipOrDir);\n$targetDir = realpath(GRAV_ROOT . '/index.php') ? dirname(realpath(GRAV_ROOT . '/index.php')) : null;\nif ($targetDir && $updateDir && str_starts_with($updateDir, $targetDir . DIRECTORY_SEPARATOR)) {\n    throw new \\RuntimeException('Update package lives inside the site root — move it to tmp/ first');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always keep grav-update zips in tmp/ (or any dir outside GRAV_ROOT) and install from the zip","Never extract an update package into the live webroot 'to inspect it'","If you already extracted one, remove those files (or restore a backup) before re-running direct-install"],"tags":["installer","upgrade","filesystem","grav"],"backgroundTag":"install-target-conflict","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}