getgrav/grav · error · InstallException

Could not remove the retired security.*.xss_scan_output sett

Error message

Could not remove the retired security.*.xss_scan_output settings

What it means

Postflight hook of the Grav 1.8.0 (2026-07-03) update that retires the XSS scan output settings: it removes twig_content.xss_scan_output, content.xss_scan_output and xss_allowed_iframe_hosts from user/config/system.yaml if present, saving only when something actually changed. Any Exception in that undefine/save sequence becomes InstallException 'Could not remove the retired security.*.xss_scan_output settings'. The message slightly over-names the keys — it covers all three retired settings.

Source

Thrown at system/src/Grav/Installer/updates/1.8.0_2026-07-03_0.php:42

    'postflight' =>
        function () {
            /** @var VersionUpdate $this */
            try {
                $yaml = YamlUpdater::instance(GRAV_ROOT . '/user/config/security.yaml');

                $changed = false;
                foreach (['twig_content.xss_scan_output', 'content.xss_scan_output', 'xss_allowed_iframe_hosts'] as $key) {
                    if ($yaml->exists($key)) {
                        $yaml->undefine($key);
                        $changed = true;
                    }
                }

                if ($changed) {
                    $yaml->save();
                }
            } catch (\Exception $e) {
                throw new InstallException('Could not remove the retired security.*.xss_scan_output settings', $e);
            }
        }
];

View on GitHub (pinned to 6040efed04)

Solutions

  1. Fix write permissions/ownership on user/config/system.yaml and re-run direct-install — removal re-executes cleanly
  2. Alternatively pre-clean the keys manually: delete twig_content.xss_scan_output, content.xss_scan_output and xss_allowed_iframe_hosts from system.yaml before upgrading
  3. Inspect the chained previous exception for the exact write/parse failure

Example fix

# before (system.yaml still has retired keys, file not writable)
twig_content:
  xss_scan_output: encode

# after — remove the retired block, then re-run the updater
twig_content: {  }
Defensive patterns

Strategy: try-catch

Validate before calling

// Remove retired keys manually before upgrading to sidestep the postflight write
$file = GRAV_ROOT . '/user/config/system.yaml';
$yaml = \Symfony\Component\Yaml\Yaml::parseFile($file);
foreach (['twig_content', 'content'] as $k) {
    if (isset($yaml[$k]['xss_scan_output'])) unset($yaml[$k]['xss_scan_output']);
}
unset($yaml['xss_allowed_iframe_hosts']);
file_put_contents($file, \Symfony\Component\Yaml\Yaml::dump($yaml, 10));

Try / catch

try {
    Install::instance()->run();
} catch (InstallException $e) {
    if (str_contains($e->getMessage(), 'retired security')) {
        // Core files are already updated; only the config cleanup failed.
        // Inspect getPrevious() for the I/O cause, fix permissions, re-run or clean the keys by hand.
    }
}

Prevention

When it happens

Trigger: user/config/system.yaml containing one of the retired keys AND being unwritable/locked/corrupt at update time; permission mismatch when direct-install runs as a different user than the file owner; invalid YAML blocking the updater's rewrite.

Common situations: Sites hardened with custom xss_scan_output / iframe-host allowlists being upgraded; config files owned by the web server while gpm runs as root or a deploy user.

Related errors


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