{"record":{"id":"eea53cbb7dcdc889","repo":"composer/composer","slug":"invalid-custom-dependency-policy-name-s-this-n","errorCode":null,"errorMessage":"Invalid custom dependency policy name \"%s\": this name is reserved for a built-in dependency policy.","messagePattern":"Invalid custom dependency policy name \"(.+?)\": this name is reserved for a built-in dependency policy\\.","errorType":"exception","errorClass":"UnexpectedValueException","httpStatus":null,"severity":"error","filePath":"src/Composer/Policy/PolicyConfig.php","lineNumber":139,"sourceCode":"    }\n\n    /**\n     * Reject custom-list names that collide with reserved or future-reserved\n     * identifiers (RESERVED_NAMES, FUTURE_RESERVED_NAMES, or any\n     * FUTURE_RESERVED_PREFIXES entry).\n     *\n     * In the normal fromConfig flow, built-in list keys (`advisories`, `malware`,\n     * `abandoned`) and known non-list sibling keys (`ignore-unreachable`) are\n     * filtered out before this check. The RESERVED_NAMES check is therefore\n     * defence-in-depth for `advisories` and `abandoned` if that loop skip ever\n     * changes; `malware` is intentionally absent from RESERVED_NAMES because\n     * repositories are allowed to advertise a `malware` list, so it relies\n     * solely on the loop's BUILTIN_LIST_NAMES skip.\n     */\n    private static function assertCustomListNameAllowed(string $listName): void\n    {\n        if (in_array($listName, self::RESERVED_NAMES, true)) {\n            throw new \\UnexpectedValueException(sprintf(\n                'Invalid custom dependency policy name \"%s\": this name is reserved for a built-in dependency policy.',\n                $listName\n            ));\n        }\n\n        $error = self::getFutureReservedListNameError($listName);\n        if ($error !== null) {\n            throw new \\UnexpectedValueException('Invalid custom dependency policy name: '.$error);\n        }\n    }\n\n    /**\n     * Reads config.policy with BC fallback to config.audit.\n     */\n    public static function fromConfig(Config $config): self\n    {\n        $policyRaw = $config->get('policy');\n        $auditRaw = $config->get('audit');","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/composer/composer/blob/6ffc1177404d0c50119c22dde6564a380f4a82c9/src/Composer/Policy/PolicyConfig.php#L121-L157","documentation":"Thrown by PolicyConfig::assertCustomListNameAllowed() when a custom dependency-policy list name collides with a built-in reserved name (the RESERVED_NAMES set, currently 'advisories' and 'abandoned'). Repositories and users must not advertise a custom list under these names because Composer routes them to the dedicated built-in policy config.","triggerScenarios":"Defining `config.policy.advisories` or `config.policy.abandoned` as a custom list name, or a repository advertising a list named 'advisories'/'abandoned'. Reached at PolicyConfig.php:139 when in_array($listName, RESERVED_NAMES, true) is true.","commonSituations":"Repo publisher reuses a built-in name for a bespoke list; user pastes a config snippet that names a custom list 'abandoned'; tooling that synthesises list names from package metadata without filtering reserved words.","solutions":["Rename the custom list to a non-reserved identifier (e.g. 'internal-advisories', 'legacy-abandoned').","Use the dedicated built-in config shape for advisories/abandoned/malware rather than a custom list.","Cross-check proposed list names against PolicyConfig::RESERVED_NAMES and PolicyConfig::BUILTIN_LIST_NAMES before publishing."],"exampleFix":"// before\n['policy' => ['abandoned' => /* custom list config */]]\n\n// after\n['policy' => ['internal-abandoned' => /* custom list config */]]","handlingStrategy":"validation","validationCode":"function listNameIsNotReserved(string $name): bool {\n    return !in_array($name, \\Composer\\Policy\\PolicyConfig::RESERVED_NAMES, true)\n        && !in_array($name, \\Composer\\Policy\\PolicyConfig::BUILTIN_LIST_NAMES, true);\n}","typeGuard":"function isReservedListName(string $name): bool {\n    return in_array($name, \\Composer\\Policy\\PolicyConfig::RESERVED_NAMES, true);\n}","tryCatchPattern":null,"preventionTips":["Namespace custom list names with an org/vendor prefix to avoid collisions.","Cross-check names against RESERVED_NAMES and BUILTIN_LIST_NAMES before publishing a repo config.","Add a CI lint that rejects reserved names in policy config."],"tags":["policy","configuration","validation","reserved-name"],"analyzedSha":"6ffc1177404d0c50119c22dde6564a380f4a82c9","analyzedAt":"2026-08-07T00:01:08.491Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}