{"record":{"id":"89f78cd900fbab98","repo":"rectorphp/rector","slug":"your-config-uses-withphp-and-withphplevel","errorCode":null,"errorMessage":"Your config uses \"withPhp*()\" and \"withPhpLevel()\" methods at the same time.%sPick one of them to avoid rule conflicts.","messagePattern":"Your config uses \"withPhp\\*\\(\\)\" and \"withPhpLevel\\(\\)\" methods at the same time\\.(.+?)Pick one of them to avoid rule conflicts\\.","errorType":"exception","errorClass":"InvalidConfigurationException","httpStatus":null,"severity":"error","filePath":"src/Configuration/RectorConfigBuilder.php","lineNumber":179,"sourceCode":"    {\n        if ($this->setGroups !== [] || $this->setProviders !== []) {\n            $setProviderCollector = new SetProviderCollector(array_map(\\Closure::fromCallable([$rectorConfig, 'make']), \\array_keys($this->setProviders)));\n            $setManager = new SetManager($setProviderCollector, new InstalledPackageResolver(getcwd()));\n            $this->groupLoadedSets = $setManager->matchBySetGroups($this->setGroups);\n            SimpleParameterProvider::addParameter(\\Rector\\Configuration\\Option::COMPOSER_BASED_SETS, $this->groupLoadedSets);\n        }\n        // not to miss it by accident\n        if ($this->isWithPhpSetsUsed === \\true) {\n            $this->sets[] = SetList::PHP_POLYFILLS;\n        }\n        if ($this->pickedPhpSetsVersion !== null) {\n            SimpleParameterProvider::setParameter(\\Rector\\Configuration\\Option::POLYFILL_CEILING_PHP_VERSION, $this->pickedPhpSetsVersion);\n        }\n        // merge sets together\n        $this->sets = array_merge($this->sets, $this->groupLoadedSets);\n        $uniqueSets = array_unique($this->sets);\n        if ($this->isWithPhpLevelUsed && $this->isWithPhpSetsUsed) {\n            throw new InvalidConfigurationException(sprintf('Your config uses \"withPhp*()\" and \"withPhpLevel()\" methods at the same time.%sPick one of them to avoid rule conflicts.', \\PHP_EOL));\n        }\n        foreach (self::LEVEL_METHOD_TO_SET as $levelMethod => [$setFilePath, $setTitle]) {\n            if (!isset($this->usedLevelMethods[$levelMethod])) {\n                continue;\n            }\n            if (!in_array($setFilePath, $uniqueSets, \\true)) {\n                continue;\n            }\n            throw new InvalidConfigurationException(sprintf('Your config already enables %s set.%sRemove \"->%s()\" as it only duplicates it, or remove %s set.', $setTitle, \\PHP_EOL, $levelMethod, $setTitle));\n        }\n        if ($uniqueSets !== []) {\n            $rectorConfig->sets($uniqueSets);\n        }\n        // log rules from sets and compare them with explicit rules\n        $setRegisteredRectorClasses = $rectorConfig->getMainRectorClasses();\n        SimpleParameterProvider::addParameter(\\Rector\\Configuration\\Option::SET_REGISTERED_RULES, $setRegisteredRectorClasses);\n        if ($this->paths !== []) {\n            $rectorConfig->paths($this->paths);","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/rectorphp/rector/blob/408fcb0ff1833e3d26cbc9b04c23a77565814a16/src/Configuration/RectorConfigBuilder.php#L161-L197","documentation":"RectorConfigBuilder applies your config lazily and cross-checks flags: if both withPhpLevel() and any withPhp*() sets method (withPhpSets/withPhpSets() variants) were called, it throws InvalidConfigurationException, because each independently builds the PHP upgrade rule list and combining them causes conflicting, duplicated rules. Pick exactly one strategy for PHP-version upgrades.","triggerScenarios":"A rector.php that contains both ->withPhpLevel(82) and ->withPhpSets() (or withPhpSets(php82: true)), often left over after migrating from the old level API to the newer sets API.","commonSituations":"Merging an old config snippet (withPhpLevel) with a freshly generated one (withPhpSets) during upgrades; copy-pasting examples from different Rector eras into one rector.php.","solutions":["Keep ->withPhpSets() (no args picks the version from composer.json) and delete the withPhpLevel() line","Or keep ->withPhpLevel(n) and remove every withPhp*() call","Re-generate a baseline config: vendor/bin/rector init and merge your custom rules into it"],"exampleFix":"// before\nreturn RectorConfig::configure()\n    ->withPhpSets(php82: true)\n    ->withPhpLevel(82);\n\n// after\nreturn RectorConfig::configure()\n    ->withPhpSets();  // version resolved from composer.json","handlingStrategy":"validation","validationCode":"// static guard in a config lint step: forbid mixing the two APIs\n$config = file_get_contents('rector.php');\nif (preg_match('/withPhpLevel\\s*\\(/', $config) && preg_match('/withPhpSets\\s*\\(/', $config)) {\n    fwrite(STDERR, \"rector.php mixes withPhpLevel() and withPhpSets(); pick one\\n\");\n    exit(1);\n}","typeGuard":null,"tryCatchPattern":"catch \\Rector\\Exception\\Configuration\\InvalidConfigurationException in config-loading tests; assert your checked-in rector.php never triggers it.","preventionTips":["Standardize on withPhpSets() with no arguments (composer.json-driven) in all projects","Delete withPhpLevel() lines during upgrade migrations instead of commenting them out","Run `vendor/bin/rector process src --dry-run` in CI so config conflicts fail fast"],"tags":["php","rector","config","conflict","php-version","migration"],"backgroundTag":"conflicting-config-options","analyzedSha":"408fcb0ff1833e3d26cbc9b04c23a77565814a16","analyzedAt":"2026-08-21T05:11:02.643Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}