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
- Enable only the LOWEST PHP version you must support, e.g. withDowngradeSets(php80: true); every rule down to that version is included automatically
- Remove the extra true flags one by one until exactly one remains
- If you genuinely need several independent levels, use withSets([...]) with explicit DowngradeLevelSetList constants instead
- 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
- Treat the lowest supported PHP version as the single source of truth in one env/parameter, then set only that flag
- Add a config smoke test that instantiates the builder and runs withDowngradeSets() with your production flags
- Remember downgrade sets are cumulative — enabling more than one target is always redundant, never additive
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
- Your config uses "withPhp*()" and "withPhpLevel()" methods a
- Pick only one version target in "withPhpSets()". All rules u
- The "->withPhpSets()" method uses named arguments. Its suita
- "%s" rule is deprecated, as inverting nested ifs to early re
- "%s" rule is deprecated, as splitting a single condition int
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/efc802aaeac89664.
Report an issue: GitHub.