Skip to content

Safari 26.4 WebTransport handshake fails (first Safari WT release) #262

@briantopping

Description

@briantopping

Environment

  • quic-go v0.59.0
  • webtransport-go v0.10.0
  • Safari 26.4 (arm64, macOS) — first Safari version with stable WebTransport
  • Chrome 146 works perfectly against the same server

Symptoms

  • Safari's new WebTransport(url).ready promise never resolves or rejects
  • The QUIC handshake starts: Safari sends INITIAL, server responds with full TLS ServerHello + certificate chain (5x 1280-byte packets)
  • Safari never completes the TLS handshake — no follow-up packets
  • Chrome connects instantly to the same endpoint

Server configuration

  • webtransport.ConfigureHTTP3Server(h3Server) called
  • TLS config: NextProtos: []string{"h3"}
  • Let's Encrypt wildcard cert with full chain (leaf + intermediate)
  • Added SETTINGS codepoints for broader draft coverage:
    • 0xc671706a (draft-07-12 SETTINGS_ENABLE_WEBTRANSPORT)
    • 0x14e9cd29 (draft-13-14 SETTINGS_WT_MAX_SESSIONS)
    • Flow control settings (0x2b64, 0x2b65, 0x2b61)
  • Added :protocol header normalization ("webtransport-h3""webtransport")

Analysis

Safari 26.4 is the first Safari version with WebTransport (marked "stable" in Feature Flags). The TLS/QUIC handshake exchanges packets but never establishes an HTTP/3 session. We suspect either:

  1. Safari uses a SETTINGS codepoint not covered by our additions
  2. Safari's QUIC version negotiation differs from Chrome
  3. A TLS extension mismatch between Safari and quic-go

We've confirmed the network path is fine (raw UDP reaches the server), the cert is valid, and Chrome works. This appears to be a Safari ↔ quic-go/webtransport-go compatibility issue.

Steps to reproduce

  1. Start a webtransport-go server with default config + ConfigureHTTP3Server
  2. Open Safari 26.4 on macOS
  3. Run in DevTools: new WebTransport('https://your-server/wt').ready.then(() => console.log('ok')).catch(e => console.log(e))
  4. Promise hangs indefinitely
  5. Same test in Chrome 146 resolves immediately

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions