What
When HTTP2ClientTransport.Posix is constructed with a .unixDomainSocket(path:) target and no explicit config.http2.authority, the :authority pseudo-header is set to the URL-encoded socket path. Servers that strictly validate :authority per RFC 7540 reject the request with RST_STREAM(PROTOCOL_ERROR).
The most common impact is interop with Rust tonic gRPC servers — its underlying hyperium/h2 layer rejects malformed authority values. Surface error in Swift:
unavailable: Stream unexpectedly closed: received RST_STREAM frame (0x1: protocol error)
Reproduction
A grpc-swift-nio-transport client targeting .unixDomainSocket(path:) without overriding the authority will emit something like:
:authority: %2Ftmp%2Fmy-socket.sock
That value violates RFC 7540 §8.1.2.3, which constrains :authority to [userinfo@]host[:port] — a percent-encoded filesystem path is not a valid form.
Root cause
NameResolver+UDS.swift:76:
authority: target.authority ?? target.address.path
The fallback is the socket path. That string then flows into PercentEncoding.encodeAuthority(...) at GRPCChannel.swift:101 and is emitted as the pseudo-header value.
What other implementations do
The grpc-swift server-side doesn't validate :authority content, so Swift-client → Swift-server happens to work — but Swift-client → tonic-server (or any RFC-7540-strict server) fails.
Workaround
Setting config.http2.authority = "localhost" overrides the resolver fallback and unblocks interop:
var config = HTTP2ClientTransport.Posix.Config.defaults
config.http2.authority = \"localhost\"
let transport = try HTTP2ClientTransport.Posix(
target: .unixDomainSocket(path: socketPath),
transportSecurity: .plaintext,
config: config,
)
Suggested fix
For UDS targets where the caller hasn't supplied an authority, default to \"localhost\" to match the convention adopted across the gRPC ecosystem. Concretely in NameResolvers.UnixDomainSocket.resolver(for:):
- authority: target.authority ?? target.address.path
+ authority: target.authority ?? \"localhost\"
This is also consistent with the ecosystem expectation that :authority is not used for routing on UDS — the address itself selects the destination.
Happy to send a PR if helpful.
Versions
- grpc-swift-nio-transport: 2.7.0 (also confirmed on
main HEAD as of 2026-04-28)
- grpc-swift-2: 2.4.0
- Swift: 6.x / Xcode 26.4
- macOS 25.4
What
When
HTTP2ClientTransport.Posixis constructed with a.unixDomainSocket(path:)target and no explicitconfig.http2.authority, the:authoritypseudo-header is set to the URL-encoded socket path. Servers that strictly validate:authorityper RFC 7540 reject the request withRST_STREAM(PROTOCOL_ERROR).The most common impact is interop with Rust tonic gRPC servers — its underlying hyperium/h2 layer rejects malformed authority values. Surface error in Swift:
Reproduction
A grpc-swift-nio-transport client targeting
.unixDomainSocket(path:)without overriding the authority will emit something like:That value violates RFC 7540 §8.1.2.3, which constrains
:authorityto[userinfo@]host[:port]— a percent-encoded filesystem path is not a valid form.Root cause
NameResolver+UDS.swift:76:The fallback is the socket path. That string then flows into
PercentEncoding.encodeAuthority(...)atGRPCChannel.swift:101and is emitted as the pseudo-header value.What other implementations do
localhostas the default authority for UDS targets.localhost.localhost.The grpc-swift server-side doesn't validate
:authoritycontent, so Swift-client → Swift-server happens to work — but Swift-client → tonic-server (or any RFC-7540-strict server) fails.Workaround
Setting
config.http2.authority = "localhost"overrides the resolver fallback and unblocks interop:Suggested fix
For UDS targets where the caller hasn't supplied an authority, default to
\"localhost\"to match the convention adopted across the gRPC ecosystem. Concretely inNameResolvers.UnixDomainSocket.resolver(for:):This is also consistent with the ecosystem expectation that
:authorityis not used for routing on UDS — the address itself selects the destination.Happy to send a PR if helpful.
Versions
mainHEAD as of 2026-04-28)