composer/composer · error · UnexpectedValueException
Invalid custom dependency policy name "%s": this name is res
Error message
Invalid custom dependency policy name "%s": this name is reserved for a built-in dependency policy.
What it means
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.
Source
Thrown at src/Composer/Policy/PolicyConfig.php:139
}
/**
* Reject custom-list names that collide with reserved or future-reserved
* identifiers (RESERVED_NAMES, FUTURE_RESERVED_NAMES, or any
* FUTURE_RESERVED_PREFIXES entry).
*
* In the normal fromConfig flow, built-in list keys (`advisories`, `malware`,
* `abandoned`) and known non-list sibling keys (`ignore-unreachable`) are
* filtered out before this check. The RESERVED_NAMES check is therefore
* defence-in-depth for `advisories` and `abandoned` if that loop skip ever
* changes; `malware` is intentionally absent from RESERVED_NAMES because
* repositories are allowed to advertise a `malware` list, so it relies
* solely on the loop's BUILTIN_LIST_NAMES skip.
*/
private static function assertCustomListNameAllowed(string $listName): void
{
if (in_array($listName, self::RESERVED_NAMES, true)) {
throw new \UnexpectedValueException(sprintf(
'Invalid custom dependency policy name "%s": this name is reserved for a built-in dependency policy.',
$listName
));
}
$error = self::getFutureReservedListNameError($listName);
if ($error !== null) {
throw new \UnexpectedValueException('Invalid custom dependency policy name: '.$error);
}
}
/**
* Reads config.policy with BC fallback to config.audit.
*/
public static function fromConfig(Config $config): self
{
$policyRaw = $config->get('policy');
$auditRaw = $config->get('audit');View on GitHub (pinned to 6ffc117740)
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.
Example fix
// before ['policy' => ['abandoned' => /* custom list config */]] // after ['policy' => ['internal-abandoned' => /* custom list config */]]
Defensive patterns
Strategy: validation
Validate before calling
function listNameIsNotReserved(string $name): bool {
return !in_array($name, \Composer\Policy\PolicyConfig::RESERVED_NAMES, true)
&& !in_array($name, \Composer\Policy\PolicyConfig::BUILTIN_LIST_NAMES, true);
} Type guard
function isReservedListName(string $name): bool {
return in_array($name, \Composer\Policy\PolicyConfig::RESERVED_NAMES, true);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid custom dependency policy name: {error}
- Built-in dependency policy "{name}" does not support sources
- Invalid ignore-id entry at index %d: expected an advisory ID
- Invalid ignore-id entry for "%s": value of type %s is not a
- Invalid ignore rule for "%s": expected an object, got %s.
AI-assisted analysis of composer/composer@6ffc117740 (2026-08-07).
Data as JSON: /api/errors/eea53cbb7dcdc889.
Report an issue: GitHub.