Root packages.json declares:
"metadata-url": "/p2/%package%.json"
But /p2/wp-plugin/akismet.json and /p2/wp-theme/twentytwentyfive.json both return:
{"packages": {"wp-plugin/akismet": {"2.2.5": {...}, "2.2.6": {...}}}}
packages[name] is a version-keyed object (dict). Per Composer's UPGRADE-2.0.md / doc/05-repositories.md, a metadata-url response MUST be an array of version objects:
{"packages": {"vendor/pkg": [{...}, {...}]}}
The object form is only valid for the legacy root packages.json — never for metadata-url/p2 responses.
Impact: Composer CLI tolerates the object form and works around it silently, but strict v2 consumers (e.g. JFrog Artifactory's remote-repo parser) reject it outright with a 500/deserialization error, since they parse per the written spec rather than Composer's lenient behavior.
Repro:
curl -s https://repo.wp-packages.org/p2/wp-plugin/akismet.json | jq '.packages["wp-plugin/akismet"] | type'
→ "object" (expected "array")
Root packages.json declares:
But
/p2/wp-plugin/akismet.jsonand/p2/wp-theme/twentytwentyfive.jsonboth return:{"packages": {"wp-plugin/akismet": {"2.2.5": {...}, "2.2.6": {...}}}}packages[name]is a version-keyed object (dict). Per Composer's UPGRADE-2.0.md / doc/05-repositories.md, a metadata-url response MUST be an array of version objects:{"packages": {"vendor/pkg": [{...}, {...}]}}The object form is only valid for the legacy root packages.json — never for metadata-url/p2 responses.
Impact: Composer CLI tolerates the object form and works around it silently, but strict v2 consumers (e.g. JFrog Artifactory's remote-repo parser) reject it outright with a 500/deserialization error, since they parse per the written spec rather than Composer's lenient behavior.
Repro:
→
"object"(expected"array")