Startram's reverse proxy sends duplicate Server headers in HTTP responses. This is malformed per RFC 9110 §5.5 which defines Server as a singleton field.
This has been silently tolerated by most HTTP clients historically, but it recently surfaced as a breaking issue when aiohttp 3.13.4 introduced strict singleton header enforcement in its C extension parser. Any client using aiohttp 3.13.4 that connects to a Startram-hosted ship will get a hard 400 error before the connection is established:
aiohttp.client_exceptions.ClientResponseError: 400,
message="Duplicate 'Server' header found.",
url='https://<ship>.startram.io/~/login'
aiohttp 3.13.5 reverted response-side parsing back to lax mode, so the immediate client-side breakage is resolved, but the underlying issue is on the Startram side. Any HTTP client that strictly enforces RFC 9110 singleton headers will hit this.
Expected behavior: The reverse proxy should emit a single Server header per response.
To reproduce: Make any HTTP request to a Startram-hosted ship URL:
curl -si -X POST "https://<ship>.startram.io/" | grep -i "^server:"
and inspect the raw response headers. You'll see two Server entries when there should only be one:
server: Caddy
server: urbit/vere-4.3
Caddy is forwarding the upstream Server header from the Urbit runtime rather than replacing it.
Came up while testing a Tlon connector for hermes-agent. The aiohttp 3.13.4 upgrade broke it, and a comment was left on the relevant PR.
Startram's reverse proxy sends duplicate Server headers in HTTP responses. This is malformed per RFC 9110 §5.5 which defines Server as a singleton field.
This has been silently tolerated by most HTTP clients historically, but it recently surfaced as a breaking issue when aiohttp 3.13.4 introduced strict singleton header enforcement in its C extension parser. Any client using aiohttp 3.13.4 that connects to a Startram-hosted ship will get a hard 400 error before the connection is established:
aiohttp 3.13.5 reverted response-side parsing back to lax mode, so the immediate client-side breakage is resolved, but the underlying issue is on the Startram side. Any HTTP client that strictly enforces RFC 9110 singleton headers will hit this.
Expected behavior: The reverse proxy should emit a single Server header per response.
To reproduce: Make any HTTP request to a Startram-hosted ship URL:
curl -si -X POST "https://<ship>.startram.io/" | grep -i "^server:"and inspect the raw response headers. You'll see two Server entries when there should only be one:
Caddy is forwarding the upstream Server header from the Urbit runtime rather than replacing it.
Came up while testing a Tlon connector for hermes-agent. The aiohttp 3.13.4 upgrade broke it, and a comment was left on the relevant PR.