composer/composer · error · InvalidArgumentException

Package is not installed: {initial}

Error message

Package is not installed: {initial}

What it means

Thrown by NoopInstaller::update() when the installed repository lacks the $initial package. NoopInstaller is used for dry runs; it still validates that the source package is registered before swapping entries (NoopInstaller.php:84-86).

Source

Thrown at src/Composer/Installer/NoopInstaller.php:85

    /**
     * @inheritDoc
     */
    public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
    {
        if (!$repo->hasPackage($package)) {
            $repo->addPackage(clone $package);
        }

        return \React\Promise\resolve(null);
    }

    /**
     * @inheritDoc
     */
    public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
    {
        if (!$repo->hasPackage($initial)) {
            throw new \InvalidArgumentException('Package is not installed: '.$initial);
        }

        $repo->removePackage($initial);
        if (!$repo->hasPackage($target)) {
            $repo->addPackage(clone $target);
        }

        return \React\Promise\resolve(null);
    }

    /**
     * @inheritDoc
     */
    public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
    {
        if (!$repo->hasPackage($package)) {
            throw new \InvalidArgumentException('Package is not installed: '.$package);
        }

View on GitHub (pinned to 6ffc117740)

Solutions

  1. Run `composer install` first so the local repo matches the lock before dry-run updates.
  2. Ensure the dry run is executed against a coherent repository state.
  3. Skip update operations for packages already absent from the repo.

Example fix

// before
$installer->update($repo, $initial, $target); // NoopInstaller dry run, $initial missing

// after
shell_exec('composer install'); // reconcile, then retry the dry-run update
Defensive patterns

Strategy: validation

Validate before calling

if (!$repo->hasPackage($initial)) {
    if (!$repo->hasPackage($target)) {
        $installer->install($repo, $target);
    }
    return;
}
$installer->update($repo, $initial, $target);

Try / catch

try {
    $installer->update($repo, $initial, $target);
} catch (\InvalidArgumentException $e) {
    // dry-run against desynced repo: reconcile, then re-run the simulation
}

Prevention

When it happens

Trigger: Running a dry-run update where $repo->hasPackage($initial) is false — the simulated update targets a package the local repo doesn't track.

Common situations: Dry-running an update against a desynced installed.json; vendored state altered before the dry run; re-running a dry-run update after state changed.

Related errors


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