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

  1. Use one of the allowed values: `composer create-project vendor/project --stability=beta`.
  2. Omit --stability and pin via the version argument instead (e.g. `vendor/project:^2@dev`).
  3. 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

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


AI-assisted analysis of composer/composer@c435d285c9 (2026-08-07). Data as JSON: /api/errors/05efd74e14a5d7a2. Report an issue: GitHub.