rectorphp/rector · error · InvalidConfigurationException

Pick only one PHP version target in "withDowngradeSets()". A

Error message

Pick only one PHP version target in "withDowngradeSets()". All rules down to this version will be used.

What it means

RectorConfigBuilder::withDowngradeSets() accepts nine boolean flags (php84 down to php71) and resolves exactly one target level via array_filter/array_keys. Downgrade rule sets are cumulative, so one target automatically includes every set above it; passing zero flags or more than one true flag is ambiguous and throws InvalidConfigurationException before any set is registered.

Source

Thrown at src/Configuration/RectorConfigBuilder.php:773

        $this->registerServices[] = new RegisteredService($className, $alias, $tag);
        return $this;
    }
    /**
     * DX helper
     * @see https://getrector.com/documentation/creating-a-node-visitor
     * @param class-string $decoratingNodeVisitorClass
     */
    public function registerDecoratingNodeVisitor(string $decoratingNodeVisitorClass): self
    {
        Assert::isAOf($decoratingNodeVisitorClass, NodeVisitor::class);
        $this->registerServices[] = new RegisteredService($decoratingNodeVisitorClass, null, DecoratingNodeVisitorInterface::class);
        return $this;
    }
    public function withDowngradeSets(bool $php84 = \false, bool $php83 = \false, bool $php82 = \false, bool $php81 = \false, bool $php80 = \false, bool $php74 = \false, bool $php73 = \false, bool $php72 = \false, bool $php71 = \false): self
    {
        $pickedDowngradeSets = array_keys(array_filter([DowngradeLevelSetList::DOWN_TO_PHP_84 => $php84, DowngradeLevelSetList::DOWN_TO_PHP_83 => $php83, DowngradeLevelSetList::DOWN_TO_PHP_82 => $php82, DowngradeLevelSetList::DOWN_TO_PHP_81 => $php81, DowngradeLevelSetList::DOWN_TO_PHP_80 => $php80, DowngradeLevelSetList::DOWN_TO_PHP_74 => $php74, DowngradeLevelSetList::DOWN_TO_PHP_73 => $php73, DowngradeLevelSetList::DOWN_TO_PHP_72 => $php72, DowngradeLevelSetList::DOWN_TO_PHP_71 => $php71]));
        if (count($pickedDowngradeSets) !== 1) {
            throw new InvalidConfigurationException('Pick only one PHP version target in "withDowngradeSets()". All rules down to this version will be used.');
        }
        $this->sets[] = $pickedDowngradeSets[0];
        return $this;
    }
    public function withRealPathReporting(bool $absolutePath = \true): self
    {
        $this->reportingRealPath = $absolutePath;
        return $this;
    }
    /**
     * Report skips configured via withSkip() that never matched anything during the run,
     * so they can be safely removed.
     */
    public function reportUnusedSkips(bool $report = \true): self
    {
        $this->reportUnusedSkips = $report;
        return $this;
    }

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Enable only the LOWEST PHP version you must support, e.g. withDowngradeSets(php80: true); every rule down to that version is included automatically
  2. Remove the extra true flags one by one until exactly one remains
  3. If you genuinely need several independent levels, use withSets([...]) with explicit DowngradeLevelSetList constants instead
  4. Run vendor/bin/rector and confirm the InvalidConfigurationException no longer triggers before committing

Example fix

// before
return $rectorConfigBuilder->withDowngradeSets(php82: true, php80: true);

// after: one target; sets above PHP 8.0 are included automatically
return $rectorConfigBuilder->withDowngradeSets(php80: true);
Defensive patterns

Strategy: validation

Validate before calling

// before building config: exactly one downgrade flag may be true
$flags = ['php84' => $php84, 'php83' => $php83, 'php82' => $php82, 'php81' => $php81,
    'php80' => $php80, 'php74' => $php74, 'php73' => $php73, 'php72' => $php72, 'php71' => $php71];
if (count(array_filter($flags)) !== 1) {
    throw new InvalidArgumentException('withDowngradeSets(): enable exactly one (the lowest) PHP target.');
}
$builder->withDowngradeSets(...array_filter($flags));

Try / catch

try {
    $builder->withDowngradeSets(php80: true);
} catch (InvalidConfigurationException $e) {
    // surface to the user editing rector.php with the offending flags
    $logger->error($e->getMessage());
}

Prevention

When it happens

Trigger: Calling withDowngradeSets() with no arguments, or with two or more flags set to true, e.g. withDowngradeSets(php82: true, php80: true). The count($pickedDowngradeSets) !== 1 check fires on both 0 and >= 2 selections.

Common situations: Migrating a config from withPhpSets() (where named arguments imply one version) to the downgrade API and enabling several levels 'to be safe'; or an editor/rector-upgrade tool commenting flags in and leaving none enabled.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21). Data as JSON: /api/errors/efc802aaeac89664. Report an issue: GitHub.