{"record":{"id":"3211f8db6be41c1c","repo":"rectorphp/rector","slug":"method-s-can-be-called-only-once-it-always-i","errorCode":null,"errorMessage":"Method \"%s()\" can be called only once. It always includes all previous sets UP TO the defined version.%sThe best practise is to call it once with no argument. That way it will pick up PHP version from composer.json and your project will always stay up to date.","messagePattern":"Method \"(.+?)\\(\\)\" can be called only once\\. It always includes all previous sets UP TO the defined version\\.(.+?)The best practise is to call it once with no argument\\. That way it will pick up PHP version from composer\\.json and your project will always stay up to date\\.","errorType":"exception","errorClass":"InvalidConfigurationException","httpStatus":null,"severity":"error","filePath":"src/Configuration/RectorConfigBuilder.php","lineNumber":409,"sourceCode":"        bool $php81 = \\false,\n        bool $php80 = \\false,\n        bool $php74 = \\false,\n        bool $php73 = \\false,\n        bool $php72 = \\false,\n        bool $php71 = \\false,\n        bool $php70 = \\false,\n        bool $php56 = \\false,\n        bool $php55 = \\false,\n        bool $php54 = \\false,\n        bool $php53 = \\false,\n        // place on later as BC break when used in php 7.x without named arg\n        bool $php84 = \\false,\n        bool $php85 = \\false,\n        bool $php86 = \\false\n    ): self\n    {\n        if ($this->isWithPhpSetsUsed === \\true) {\n            throw new InvalidConfigurationException(sprintf('Method \"%s()\" can be called only once. It always includes all previous sets UP TO the defined version.%sThe best practise is to call it once with no argument. That way it will pick up PHP version from composer.json and your project will always stay up to date.', __METHOD__, \\PHP_EOL));\n        }\n        $this->isWithPhpSetsUsed = \\true;\n        $pickedPhpVersions = array_keys(array_filter([PhpVersion::PHP_53 => $php53, PhpVersion::PHP_54 => $php54, PhpVersion::PHP_55 => $php55, PhpVersion::PHP_56 => $php56, PhpVersion::PHP_70 => $php70, PhpVersion::PHP_71 => $php71, PhpVersion::PHP_72 => $php72, PhpVersion::PHP_73 => $php73, PhpVersion::PHP_74 => $php74, PhpVersion::PHP_80 => $php80, PhpVersion::PHP_81 => $php81, PhpVersion::PHP_82 => $php82, PhpVersion::PHP_83 => $php83, PhpVersion::PHP_84 => $php84, PhpVersion::PHP_85 => $php85, PhpVersion::PHP_86 => $php86]));\n        if ($pickedPhpVersions !== []) {\n            Notifier::errorWithPhpSetsNotSuitableForPHP74AndLower();\n        }\n        if (count($pickedPhpVersions) > 1) {\n            throw new InvalidConfigurationException(sprintf('Pick only one version target in \"withPhpSets()\". All rules up to this version will be used.%sTo use your composer.json PHP version, keep arguments empty.', \\PHP_EOL));\n        }\n        // no version picked, resolve it from the project composer.json\n        if ($pickedPhpVersions === []) {\n            return $this->addPhpLevelSets(ComposerJsonPhpVersionResolver::resolveFromCwdOrFail());\n        }\n        // explicitly picked version is a ceiling, even for polyfilled rules\n        $this->pickedPhpSetsVersion = $pickedPhpVersions[0];\n        return $this->addPhpLevelSets($pickedPhpVersions[0]);\n    }\n    public function withPhp53Sets(): self","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/rectorphp/rector/blob/408fcb0ff1833e3d26cbc9b04c23a77565814a16/src/Configuration/RectorConfigBuilder.php#L391-L427","documentation":"withPhpSets() is designed to be called once: without arguments it picks the target PHP version from composer.json and includes all sets up to it, so a second call would either duplicate or contradict the first. RectorConfigBuilder tracks isWithPhpSetsUsed and throws InvalidConfigurationException (naming RectorConfigBuilder::withPhpSets) on the second invocation. The message recommends the zero-argument form so the project tracks composer.json automatically.","triggerScenarios":"Two ->withPhpSets(...) calls in one rector.php, e.g. ->withPhpSets(php82: true) earlier and ->withPhpSets(php74: true) added later, or an imported sub-config that also calls withPhpSets().","commonSituations":"Merging configs during refactors; importing a shared config file that itself calls withPhpSets() while the main rector.php also does.","solutions":["Keep a single call, ideally ->withPhpSets() with no arguments so the version follows composer.json","If two versions were attempted, decide the real target and delete the other call","If a shared imported config calls withPhpSets(), remove the call from the main file (or vice versa)"],"exampleFix":"// before\nreturn RectorConfig::configure()\n    ->withPhpSets(php74: true)\n    ->withPhpSets(php82: true);\n\n// after\nreturn RectorConfig::configure()\n    ->withPhpSets();  // single call, version from composer.json","handlingStrategy":"validation","validationCode":"// lint: withPhpSets must appear at most once (imports included)\n$occurrences = substr_count(file_get_contents('rector.php'), 'withPhpSets(');\n$imported = glob(__DIR__ . '/config/*.php') ?: []; // if you re-export sub-configs, count those too\nforeach ($imported as $file) {\n    $occurrences += substr_count((string) file_get_contents($file), 'withPhpSets(');\n}\nif ($occurrences > 1) {\n    fwrite(STDERR, \"withPhpSets() called {$occurrences} times; call it once\\n\");\n}","typeGuard":null,"tryCatchPattern":"catch \\Rector\\Exception\\Configuration\\InvalidConfigurationException naming withPhpSets; deduplicate to a single call (prefer zero-argument) and reload.","preventionTips":["Keep exactly one ->withPhpSets() call, ideally without arguments","Shared/imported config files must not also call withPhpSets()","During merges, grep for 'withPhpSets' to catch duplicated blocks"],"tags":["php","rector","config","duplicate","php-sets"],"backgroundTag":"duplicate-config-entries","analyzedSha":"408fcb0ff1833e3d26cbc9b04c23a77565814a16","analyzedAt":"2026-08-21T05:11:02.643Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}