getgrav/grav · error · InstallException

Could not update system configuration to maintain backwards

Error message

Could not update system configuration to maintain backwards compatibility

What it means

This is the postflight hook of the Grav 1.7.0 schema update. It uses YamlUpdater to write backward-compatibility defaults into user/config/system.yaml (twig.autoescape: false, three strict_mode.* flags) and saves; any Exception from that write is rethrown as InstallException 'Could not update system configuration to maintain backwards compatibility'. The core files have already been installed at this point — only the user config mutation failed.

Source

Thrown at system/src/Grav/Installer/updates/1.7.0_2020-11-20_1.php:21

use Grav\Installer\InstallException;
use Grav\Installer\VersionUpdate;
use Grav\Installer\YamlUpdater;

return [
    'preflight' => null,
    'postflight' =>
        function () {
            /** @var VersionUpdate $this */
            try {
                // Keep old defaults for backwards compatibility.
                $yaml = YamlUpdater::instance(GRAV_ROOT . '/user/config/system.yaml');
                $yaml->define('twig.autoescape', false);
                $yaml->define('strict_mode.yaml_compat', true);
                $yaml->define('strict_mode.twig2_compat', true);
                $yaml->define('strict_mode.blueprint_compat', true);
                $yaml->save();
            } catch (\Exception $e) {
                throw new InstallException('Could not update system configuration to maintain backwards compatibility', $e);
            }
        }
];

View on GitHub (pinned to 6040efed04)

Solutions

  1. Fix ownership/permissions so the user running direct-install can write user/config/system.yaml (e.g. `chown -R www-data:user user/config`)
  2. Validate the file first: `bin/grav yamllint user/config/system.yaml` or re-parse it with a YAML linter, and restore from backup if broken
  3. Free disk space / release locks, then re-run direct-install — the updater is idempotent

Example fix

# before
sudo php bin/gpm direct-install tmp/grav-update.zip # root writes, file owned by www-data mode 644 -> write fails

# after
sudo -u www-data php bin/gpm direct-install tmp/grav-update.zip # run as the owning user
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: config must be writable and parseable before upgrading
$file = GRAV_ROOT . '/user/config/system.yaml';
if (file_exists($file)) {
    if (!is_writable($file)) {
        throw new \RuntimeException("{$file} is not writable by " . get_current_user());
    }
    try {
        \Symfony\Component\Yaml\Yaml::parseFile($file);
    } catch (\Throwable $e) {
        throw new \RuntimeException("{$file} is not valid YAML: " . $e->getMessage());
    }
}

Try / catch

try {
    Install::instance()->run();
} catch (InstallException $e) {
    $prev = $e->getPrevious(); // the original YamlUpdater/IO failure
    fwrite(STDERR, $e->getMessage() . ': ' . ($prev ? $prev->getMessage() : 'unknown'));
    // Fix permissions/ownership, then re-run — the update hooks are idempotent
}

Prevention

When it happens

Trigger: user/config/system.yaml (or the user/config directory) being read-only or owned by another user when direct-install runs as CLI user; the file containing YAML the updater cannot parse/merge; disk full; file locked by a concurrent edit.

Common situations: CLI upgrade run as root while the file is owned by www-data (or vice versa); restored backups with wrong ownership; system.yaml hand-edited into invalid YAML before upgrading.

Related errors


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