{"record":{"id":"2ed0f9b20c97043b","repo":"composer/composer","slug":"only-subclasses-of-basepackage-are-supported","errorCode":null,"errorMessage":"Only subclasses of BasePackage are supported","messagePattern":"Only subclasses of BasePackage are supported","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Composer/Repository/ArrayRepository.php","lineNumber":218,"sourceCode":"        if ($this->packageMap === null) {\n            $this->packageMap = [];\n            foreach ($this->getPackages() as $repoPackage) {\n                $this->packageMap[$repoPackage->getUniqueName()] = $repoPackage;\n            }\n        }\n\n        return isset($this->packageMap[$package->getUniqueName()]);\n    }\n\n    /**\n     * Adds a new package to the repository\n     *\n     * @return void\n     */\n    public function addPackage(PackageInterface $package)\n    {\n        if (!$package instanceof BasePackage) {\n            throw new \\InvalidArgumentException('Only subclasses of BasePackage are supported');\n        }\n        if (null === $this->packages) {\n            $this->initialize();\n        }\n        $package->setRepository($this);\n        $this->packages[] = $package;\n\n        if ($package instanceof AliasPackage) {\n            $aliasedPackage = $package->getAliasOf();\n            if (null === $aliasedPackage->getRepository()) {\n                $this->addPackage($aliasedPackage);\n            }\n        }\n\n        // invalidate package map cache\n        $this->packageMap = null;\n    }\n","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/composer/composer/blob/c435d285c9120efdca35696769c72ea9fdcc0466/src/Composer/Repository/ArrayRepository.php#L200-L236","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom repository implementations or test doubles that pass a non-BasePackage mock. Third-party plugins that construct their own package classes.","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."],"exampleFix":"// before\n$repo->addPackage(new MyCustomPackage($name, $version, $type));\n// after\n$pkg = new \\Composer\\Package\\CompletePackage($name, $version, $prettyVersion);\n$repo->addPackage($pkg);","handlingStrategy":"type-guard","validationCode":"if (!$package instanceof \\Composer\\Package\\BasePackage) {\n    throw new \\InvalidArgumentException('Repository expects BasePackage, got '.get_debug_type($package));\n}\n$repo->addPackage($package);","typeGuard":"function isBasePackage(\\Composer\\Package\\PackageInterface $p): bool\n{\n    return $p instanceof \\Composer\\Package\\BasePackage;\n}","tryCatchPattern":"try {\n    $repo->addPackage($package);\n} catch (\\InvalidArgumentException $e) {\n    if (str_contains($e->getMessage(), 'Only subclasses of BasePackage')) { /* wrap in a BasePackage/CompletePackage */ }\n    else { throw $e; }\n}","preventionTips":["Always construct CompletePackage/BasePackage instances for repository insertion.","In tests, stub concrete BasePackage subclasses rather than the interface."],"tags":["api-misuse","repository","packages"],"backgroundTag":null,"analyzedSha":"c435d285c9120efdca35696769c72ea9fdcc0466","analyzedAt":"2026-08-07T18:58:23.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}