composer/composer · error · InvalidArgumentException
Only subclasses of BasePackage are supported
Error message
Only subclasses of BasePackage are supported
What it means
Thrown by ArrayRepository::addPackage when the supplied package does not extend BasePackage. ArrayRepository relies on BasePackage-specific behaviour (aliasing, unique-name caching) and rejects any other PackageInterface implementation.
Source
Thrown at src/Composer/Repository/ArrayRepository.php:218
if ($this->packageMap === null) {
$this->packageMap = [];
foreach ($this->getPackages() as $repoPackage) {
$this->packageMap[$repoPackage->getUniqueName()] = $repoPackage;
}
}
return isset($this->packageMap[$package->getUniqueName()]);
}
/**
* Adds a new package to the repository
*
* @return void
*/
public function addPackage(PackageInterface $package)
{
if (!$package instanceof BasePackage) {
throw new \InvalidArgumentException('Only subclasses of BasePackage are supported');
}
if (null === $this->packages) {
$this->initialize();
}
$package->setRepository($this);
$this->packages[] = $package;
if ($package instanceof AliasPackage) {
$aliasedPackage = $package->getAliasOf();
if (null === $aliasedPackage->getRepository()) {
$this->addPackage($aliasedPackage);
}
}
// invalidate package map cache
$this->packageMap = null;
}
View on GitHub (pinned to c435d285c9)
Solutions
- Ensure the package instance extends Composer\Package\BasePackage (or one of its subclasses like CompletePackage, AliasPackage).
- If using a loader, use ArrayLoader which produces BasePackage instances.
- In tests, mock or stub a concrete BasePackage subclass rather than the interface.
Example fix
// before $repo->addPackage(new MyCustomPackage($name, $version, $type)); // after $pkg = new \Composer\Package\CompletePackage($name, $version, $prettyVersion); $repo->addPackage($pkg);
Defensive patterns
Strategy: type-guard
Validate before calling
if (!$package instanceof \Composer\Package\BasePackage) {
throw new \InvalidArgumentException('Repository expects BasePackage, got '.get_debug_type($package));
}
$repo->addPackage($package); Type guard
function isBasePackage(\Composer\Package\PackageInterface $p): bool
{
return $p instanceof \Composer\Package\BasePackage;
} Try / catch
try {
$repo->addPackage($package);
} catch (\InvalidArgumentException $e) {
if (str_contains($e->getMessage(), 'Only subclasses of BasePackage')) { /* wrap in a BasePackage/CompletePackage */ }
else { throw $e; }
} Prevention
- Always construct CompletePackage/BasePackage instances for repository insertion.
- In tests, stub concrete BasePackage subclasses rather than the interface.
When it happens
Trigger: Calling $repo->addPackage($pkg) where $pkg is a PackageInterface that is not a BasePackage subclass (e.g. a bare Package or a custom implementation extending only PackageInterface). Also reachable via AliasPackage handling in addPackage itself.
Common situations: Custom repository implementations or test doubles that pass a non-BasePackage mock. Third-party plugins that construct their own package classes.
Related errors
- This function requires either an IOInterface or a Repository
- Filter api-url {apiUrl} returned an unexpected response for
- Filter summary URL {summaryUrl} returned 404 for {repoName}
- Invalid repository data in {file}, packages could not be loa
- A repository of type "package" contains an invalid package d
AI-assisted analysis of composer/composer@c435d285c9 (2026-08-07).
Data as JSON: /api/errors/2ed0f9b20c97043b.
Report an issue: GitHub.