composer/composer · error · InvalidArgumentException
Invalid stability provided (%s), must be one of: stable, RC,
Error message
Invalid stability provided (%s), must be one of: stable, RC, beta, alpha, dev
What it means
Thrown by CreateProjectCommand::installRootProject() as an InvalidArgumentException when the requested stability (after normalization) is not one of the keys in BasePackage::STABILITIES (stable, RC, beta, alpha, dev). Stability can come from --stability option, be derived from the version constraint, or default to 'stable'.
Source
Thrown at src/Composer/Command/CreateProjectCommand.php:411
if (!$fs->isDirEmpty($directory)) {
throw new \InvalidArgumentException('Project directory "'.$directory.'" is not empty.');
}
}
if (null === $stability) {
if (null === $packageVersion) {
$stability = 'stable';
} elseif (Preg::isMatchStrictGroups('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::STABILITIES)).')$}i', $packageVersion, $match)) {
$stability = $match[1];
} else {
$stability = VersionParser::parseStability($packageVersion);
}
}
$stability = VersionParser::normalizeStability($stability);
if (!isset(BasePackage::STABILITIES[$stability])) {
throw new \InvalidArgumentException('Invalid stability provided ('.$stability.'), must be one of: '.implode(', ', array_keys(BasePackage::STABILITIES)));
}
$composer = $this->createComposerInstance($input, $io, $config->all(), $disablePlugins, $disableScripts);
$config = $composer->getConfig();
// set the base dir here again on the new config instance, as otherwise in case the vendor dir is defined in an env var for example it would still override the value set above by $config->all()
$config->setBaseDir($directory);
$rm = $composer->getRepositoryManager();
$repositorySet = new RepositorySet($stability);
if (null === $repositories) {
$repositorySet->addRepository(new CompositeRepository(RepositoryFactory::defaultRepos($io, $config, $rm)));
} else {
foreach ($repositories as $repo) {
$repoConfig = RepositoryFactory::configFromString($io, $config, $repo, true);
if (
(isset($repoConfig['packagist']) && $repoConfig === ['packagist' => false])
|| (isset($repoConfig['packagist.org']) && $repoConfig === ['packagist.org' => false])
) {View on GitHub (pinned to c435d285c9)
Solutions
- Use one of the allowed values: `composer create-project vendor/project --stability=beta`.
- Omit --stability and pin via the version argument instead (e.g. `vendor/project:^2@dev`).
- For latest dev work use `--stability=dev`.
Example fix
// before composer create-project vendor/project --stability=production // after composer create-project vendor/project --stability=stable
Defensive patterns
Strategy: validation
Validate before calling
$allowed = ['stable','rc','beta','alpha','dev'];
if (!in_array(strtolower((string)$stability), $allowed, true)) {
fwrite(STDERR, "Invalid stability; use one of: ".implode(', ',$allowed)."\n"); exit(1);
} Type guard
function isStabilityValid(string $stability): bool {
return in_array(strtolower($stability), ['stable','rc','beta','alpha','dev'], true);
} Prevention
- Restrict --stability to the five Composer stability words.
- Prefer version constraints (@dev, @beta) over --stability when unsure.
When it happens
Trigger: Passing `--stability=production`, `--stability=testing`, or a version string whose @stability suffix maps to an unknown token. Also if a custom/translated stability word is supplied.
Common situations: Confusing Composer stability terms with semantic-release terms (e.g. 'production'), typos like '--stability=devl', or inheriting stability from a malformed version constraint.
Related errors
- Not enough arguments (missing: "package").
- Got an empty target directory, something went wrong
- Cannot create project directory at "%s", it exists as a file
- Project directory "%s" is not empty.
- Not enough arguments (missing: "packages").
AI-assisted analysis of composer/composer@c435d285c9 (2026-08-07).
Data as JSON: /api/errors/05efd74e14a5d7a2.
Report an issue: GitHub.