{"record":{"id":"017b36f431bc357d","repo":"composer/composer","slug":"expected-a-valid-stability-name-as-3rd-argument-g","errorCode":null,"errorMessage":"Expected a valid stability name as 3rd argument, got %s","messagePattern":"Expected a valid stability name as 3rd argument, got (.+?)","errorType":"exception","errorClass":"UnexpectedValueException","httpStatus":null,"severity":"error","filePath":"src/Composer/Package/Version/VersionSelector.php","lineNumber":75,"sourceCode":"                $this->platformConstraints[$package->getName()][] = new Constraint('==', $package->getVersion());\n            }\n        }\n    }\n\n    /**\n     * Given a package name and optional version, returns the latest PackageInterface\n     * that matches.\n     *\n     * @param PlatformRequirementFilterInterface|bool|string[] $platformRequirementFilter\n     * @param IOInterface|null                                 $io                        If passed, warnings will be output there in case versions cannot be selected due to platform requirements\n     * @param callable(PackageInterface):bool|bool             $showWarnings\n     * @return PackageInterface|false\n     */\n    public function findBestCandidate(string $packageName, ?string $targetPackageVersion = null, string $preferredStability = 'stable', $platformRequirementFilter = null, int $repoSetFlags = 0, ?IOInterface $io = null, $showWarnings = true)\n    {\n        if (!isset(BasePackage::STABILITIES[$preferredStability])) {\n            // If you get this, maybe you are still relying on the Composer 1.x signature where the 3rd arg was the php version\n            throw new \\UnexpectedValueException('Expected a valid stability name as 3rd argument, got '.$preferredStability);\n        }\n\n        if (null === $platformRequirementFilter) {\n            $platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing();\n        } elseif (!($platformRequirementFilter instanceof PlatformRequirementFilterInterface)) {\n            trigger_error('VersionSelector::findBestCandidate with ignored platform reqs as bool|array is deprecated since Composer 2.2, use an instance of PlatformRequirementFilterInterface instead.', E_USER_DEPRECATED);\n            $platformRequirementFilter = PlatformRequirementFilterFactory::fromBoolOrList($platformRequirementFilter);\n        }\n\n        $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null;\n        $candidates = $this->repositorySet->findPackages(strtolower($packageName), $constraint, $repoSetFlags);\n\n        $minPriority = BasePackage::STABILITIES[$preferredStability];\n        usort($candidates, static function (PackageInterface $a, PackageInterface $b) use ($minPriority) {\n            $aPriority = $a->getStabilityPriority();\n            $bPriority = $b->getStabilityPriority();\n\n            // A is less stable than our preferred stability,","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/composer/composer/blob/c435d285c9120efdca35696769c72ea9fdcc0466/src/Composer/Package/Version/VersionSelector.php#L57-L93","documentation":"Thrown by VersionSelector::findBestCandidate() when the $preferredStability argument (3rd positional arg) is not a key of BasePackage::STABILITIES (stable/rc/beta/alpha/dev). The inline comment notes this is specifically to catch callers still using the Composer 1.x signature, where the 3rd argument was the PHP version string rather than a stability.","triggerScenarios":"Calling $versionSelector->findBestCandidate($name, $targetVersion, $phpVersion) using the old Composer 1 calling convention where the 3rd arg was the php version (e.g. '7.4.0'), which is not a valid stability name. Also any call passing a typo'd or unsupported stability.","commonSituations":"Code/tutorials written for Composer 1 calling findBestCandidate() with a php version as the 3rd arg; passing a custom stability string that isn't one of stable/rc/beta/alpha/dev; copy-paste from outdated docs.","solutions":["Pass a valid stability as the 3rd argument (default 'stable'): findBestCandidate($name, $targetVersion, 'stable').","If you were passing a PHP version, remove it - the Composer 2 signature no longer takes php version here; platform filtering is handled via $platformRepo.","Use one of the BasePackage::STABILITIES keys: 'stable', 'rc', 'beta', 'alpha', or 'dev'.","Update code/tutorials from the Composer 1.x API to the 2.x API."],"exampleFix":"// before (Composer 1 signature - wrong)\n$versionSelector->findBestCandidate('vendor/pkg', '^2.0', '7.4.0');\n\n// after (Composer 2 signature)\n$versionSelector->findBestCandidate('vendor/pkg', '^2.0', 'stable');","handlingStrategy":"validation","validationCode":"// Validate stability against the known set before calling.\n$stability = strtolower((string) $preferredStability);\nif (!isset(\\Composer\\Package\\BasePackage::STABILITIES[$stability])) {\n    throw new \\InvalidArgumentException(\"Invalid stability: $preferredStability\");\n}\n$pkg = $selector->findBestCandidate($name, $target, $stability);","typeGuard":"/** @param string $s */\nfunction isValidStability(string $s): bool {\n    return isset(\\Composer\\Package\\BasePackage::STABILITIES[strtolower($s)]);\n}","tryCatchPattern":"try {\n    $pkg = $selector->findBestCandidate($name, $target, $preferredStability);\n} catch (\\UnexpectedValueException $e) {\n    // invalid stability - default to 'stable' (Composer 2 signature)\n    $pkg = $selector->findBestCandidate($name, $target, 'stable');\n}","preventionTips":["Use the Composer 2 signature: 3rd arg is a stability (stable/rc/beta/alpha/dev), not a php version.","Default the 3rd argument to 'stable' unless you intentionally want less stable packages.","Update code and docs migrated from Composer 1.x."],"tags":["api-migration","composer-2","version-selection","programming-error"],"backgroundTag":null,"analyzedSha":"c435d285c9120efdca35696769c72ea9fdcc0466","analyzedAt":"2026-08-07T18:58:23.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}