Abstract
This proposal recommends that Python package registries adopt RFC 9457 (Problem Details for HTTP APIs) as a standard format for error responses in PEP 503 (Simple Repository API) and PEP 691 (JSON-based Simple API). Currently, when pip encounters HTTP errors from package registries, it displays the status code and reason phrase from the HTTP response. While HTTP/1.1 includes both fields, HTTP/2 removed the reason phrase entirely, leaving developers with only numeric status codes (e.g., “403”) and no context about why a request failed. This creates a significant user experience problem as HTTP/2 adoption accelerates. This proposal enables registries to provide structured, human-readable error information through RFC 9457’s standardized JSON format, which works consistently across both HTTP/1.1 and HTTP/2. The implementation would be optional and backwards-compatible, with clients falling back to existing behavior for non-RFC 9457 responses.
Motivation
When developers retrieve Python packages from external clients (such as UV), some registries provide error context by embedding messages in the HTTP/1.1 reason phrase field. However, HTTP/2 removed this field entirely, leaving developers with only numeric status codes under modern infrastructure. Without understanding why a package was blocked, developers must contact administrators to diagnose issues, creating unnecessary friction.
Real-World Scenario (Nexus Repository Manager):
The following is how the developer sees a custom error message when trying to download component urllib3 via pip (and using HTTP/1.1 reason phrase to display a custom message):
pip download urllib3
Looking in indexes: http://<hostName>/repository/pypi-proxy/simple
Collecting urllib3
ERROR: HTTP error 403 while getting http://<hostName>/repository/pypi-proxy/packages/urllib3/...
ERROR: Could not install requirement urllib3 because of HTTP error 403 Client Error: Requested item is quarantined ...
Technical Problems with This Approach:
- HTTP/2 Incompatibility: HTTP/2 removed the reason phrase field entirely (RFC 9113). Only the numeric status code is transmitted, meaning custom messages are lost when registries use HTTP/2.
- Not Standardized: The reason phrase format is not structured, making it impossible for clients to parse and display intelligently.
- Limited Length: Reason phrases have practical length limitations and cannot convey complex structured information (e.g. multiple errors, links, metadata).
With RFC 9457, this becomes:
{
“status”: 403,
“title”: “Package quarantined by security policy”,
“detail”: “urllib3 version 2.6.2 has been quarantined due to security policy violations.”
}
Ecosystem Context
RFC 9457 is already mandated in:
- PEP 807 Index support for Trusted Publishing
- PEP 694 Upload 2.0 API for Python Package Indexes
Rationale
Why RFC 9457?
- RFC 9457 is a well-established IETF standard (published July 2023) used by major APIs.
- Provides machine-readable + human-readable error information.
- Works consistently across HTTP/1.1 and HTTP/2
- Allows registries to add custom fields for domain-specific context
Why Optional/Recommended?
Making this recommended rather than mandatory allows:
- Gradual adoption across diverse registry implementations.
- No breaking changes for existing indices.
- Progressive enhancement: clients can improve UX when RFC 9457 is detected.
Another option to support custom error messages from registries is to add a new custom header in the pip response. Similar work was done in the HuggingFace ecosystem where the header X-Error-Message is used. However, custom headers are non-standard and don’t provide structured, machine-readable error details like RFC 9457.
Specification (High-Level)
Scope: PEP 503 (Simple Repository API) and PEP 691 (JSON-based Simple API)
When Applied: HTTP error responses (4xx and 5xx status codes) from registry endpoints when pip interacts with the registry.
Minimum Required Fields:
- status (integer): HTTP status code.
- title (string): Short, human-readable summary.
- detail (string): Detailed explanation of the error.
HTTP Content-Type: application/problem+json
Example Response:
{
“status”: 403,
“title”: “Package blocked by security policy”,
“detail”: “packageABC version 1.19.0 contains CVE-2021-12345 (Critical severity). Please upgrade to version 1.21.0 or later, for more details visit:``http://host.example.com``”
}
Client Behavior:
- Clients like pip may parse and display RFC 9457 responses.
- If
Content-Type:application/problem+jsonis detected, clients can extract structured error details. - If not present, clients continue using existing error handling (fully backwards-compatible)
Related work:
- Draft PR implementing RFC 9457 for PIP: Add RFC9457 support problem details handling by luisgcoding · Pull Request #13620 · pypa/pip · GitHub
- UV project already implements RFC 9457 for error responses: Implement RFC9457 compliant messaging by doddi · Pull Request #16199 · astral-sh/uv · GitHub
What does the community think about this?. We are maintainers of a private registry and have experienced these error reporting limitations firsthand. We recognize we may not have full visibility into ecosystem-wide impacts, so we’re seeking community feedback before proposing a formal PEP.
I’m happy to collaborate with @woodruffw and others interested in moving this forward. Looking for feedback and buy-in before drafting a formal PEP.