Describe the bug
On a network where the QUIC handshake to the tunnel edge is rejected during the TLS handshake (rather than blackholed), --protocol auto never falls back to HTTP/2. It retries QUIC indefinitely with exponential backoff, registers no connections, and the tunnel stays down.
Two distinct observations, in the same run and the same second:
- No fallback. Every dial fails with
CRYPTO_ERROR 0x178 (remote): tls: no application protocol — TLS alert 120, no_application_protocol — and auto keeps retrying QUIC instead of switching transports.
- The startup precheck reports the opposite of reality. At the very moment those dials are failing,
UDP Connectivity is reported status=pass with details="QUIC connection successful" for both regions, and the run concludes suggested_protocol=quic.
This looks like the second causes the first: the precheck's UDP component appears to test reachability rather than a real tunnel handshake, so the transport-selection logic is told QUIC is usable while it demonstrably is not.
Log
--protocol auto, cloudflared 2026.7.2. run_id elided, timestamps verbatim:
15:51:33Z INF Version 2026.7.2 (Checksum 809407c3d6e78787e2b14863ea6a1d4f31712186b5fd056815d093e29e8bff26)
15:51:33Z INF GOOS: darwin, GOVersion: go1.26.5, GoArch: amd64
15:51:34Z ERR Failed to dial a quic connection error="failed to dial to edge with quic: CRYPTO_ERROR 0x178 (remote): tls: no application protocol" connIndex=0 ip=198.41.200.33
15:51:34Z INF Retrying connection in up to 2s connIndex=0 ip=198.41.200.33
15:51:35Z ERR Failed to dial a quic connection error="... tls: no application protocol" connIndex=0 ip=198.41.200.193
15:51:35Z INF Retrying connection in up to 4s connIndex=0 ip=198.41.200.193
15:51:36Z ERR Failed to dial a quic connection error="... tls: no application protocol" connIndex=0 ip=198.41.200.23
15:51:36Z INF Retrying connection in up to 8s connIndex=0 ip=198.41.200.23
15:51:40Z ERR Failed to dial a quic connection error="... tls: no application protocol" connIndex=0 ip=198.41.192.67
15:51:40Z INF Retrying connection in up to 16s connIndex=0 ip=198.41.192.67
15:51:40Z INF precheck component="DNS Resolution" details="DNS Resolved successfully" status=pass target=region1.v2.argotunnel.com
15:51:40Z INF precheck component="UDP Connectivity" details="QUIC connection successful" status=pass target=region1.v2.argotunnel.com
15:51:40Z INF precheck component="UDP Connectivity" details="QUIC connection successful" status=pass target=region2.v2.argotunnel.com
15:51:40Z INF precheck component="TCP Connectivity" details="HTTP/2 connection successful" status=pass target=region1.v2.argotunnel.com
15:51:40Z INF precheck complete hard_fail=false suggested_protocol=quic
The backoff kept growing (observed up to 1m4s). No Registered tunnel connection line ever appeared, over more than fifteen minutes, until the protocol was pinned to http2 by hand — after which all four connections registered within two seconds.
Expected behavior
After repeated QUIC dial failures, --protocol auto should fall back to HTTP/2, as documented in Run parameters. A TLS-level rejection of the QUIC handshake seems not to be classified as "QUIC is unusable" the way a timeout is.
Secondarily: UDP Connectivity should not report pass / QUIC connection successful on a path where the tunnel's own QUIC handshake is being rejected. As it stands the precheck is actively misleading — it was the reason we believed QUIC was viable here.
To Reproduce
- Be on a network that rejects the QUIC handshake to the edge rather than dropping the packets. Ours is a mobile carrier (see below) where UDP to
198.41.192.0/24 / 198.41.200.0/24 on 7844 is reachable but the handshake is refused.
cloudflared tunnel --protocol auto run --token-file ...
- Observe repeated
CRYPTO_ERROR 0x178, growing backoff, no fallback, no registered connections.
--protocol http2 on the same host and network works perfectly and has done for months.
How this differs from #749
#749 (closed, 2022) is the same expectation but a different trigger: there UDP was blocked and the symptom was i/o timeout. Here UDP reaches the edge and the failure happens inside the TLS handshake, which is presumably why it is classified differently — and why the precheck passes.
Environment and versions
- OS: macOS 15.7.7
- Architecture: x86_64
- Version: 2026.7.2, reproduced on that build.
- Also on 2026.8.3:
--protocol quic produces the identical CRYPTO_ERROR 0x178. --protocol auto was not retested on 2026.8.3 — this is a production tunnel and each attempt takes the service down, so I did not want to run it again blind. Worth noting that on 2026.8.3 the precheck did, in a later run, correctly report UDP Connectivity ... QUIC connection failed with suggested_protocol=http2, so the precheck behaviour may already differ between the two builds.
Additional context
The network-side cause is almost certainly upstream of cloudflared and I am not asking you to fix it — QUIC from this uplink reaches Google, Facebook, Akamai and Vultr over HTTP/3 fine, but times out to Cloudflare (104.18.0.0/16, 1.1.1.0/24) and Fastly (151.101.0.0/16). Path MTU is 1500 to all of them.
The report is only about the two client-side behaviours: the missing fallback, and a precheck that reports a path as healthy while that same path is failing in the same second.
Describe the bug
On a network where the QUIC handshake to the tunnel edge is rejected during the TLS handshake (rather than blackholed),
--protocol autonever falls back to HTTP/2. It retries QUIC indefinitely with exponential backoff, registers no connections, and the tunnel stays down.Two distinct observations, in the same run and the same second:
CRYPTO_ERROR 0x178 (remote): tls: no application protocol— TLS alert 120,no_application_protocol— andautokeeps retrying QUIC instead of switching transports.UDP Connectivityis reportedstatus=passwithdetails="QUIC connection successful"for both regions, and the run concludessuggested_protocol=quic.This looks like the second causes the first: the precheck's UDP component appears to test reachability rather than a real tunnel handshake, so the transport-selection logic is told QUIC is usable while it demonstrably is not.
Log
--protocol auto, cloudflared 2026.7.2.run_idelided, timestamps verbatim:The backoff kept growing (observed up to
1m4s). NoRegistered tunnel connectionline ever appeared, over more than fifteen minutes, until the protocol was pinned tohttp2by hand — after which all four connections registered within two seconds.Expected behavior
After repeated QUIC dial failures,
--protocol autoshould fall back to HTTP/2, as documented in Run parameters. A TLS-level rejection of the QUIC handshake seems not to be classified as "QUIC is unusable" the way a timeout is.Secondarily:
UDP Connectivityshould not reportpass/QUIC connection successfulon a path where the tunnel's own QUIC handshake is being rejected. As it stands the precheck is actively misleading — it was the reason we believed QUIC was viable here.To Reproduce
198.41.192.0/24/198.41.200.0/24on 7844 is reachable but the handshake is refused.cloudflared tunnel --protocol auto run --token-file ...CRYPTO_ERROR 0x178, growing backoff, no fallback, no registered connections.--protocol http2on the same host and network works perfectly and has done for months.How this differs from #749
#749 (closed, 2022) is the same expectation but a different trigger: there UDP was blocked and the symptom was
i/o timeout. Here UDP reaches the edge and the failure happens inside the TLS handshake, which is presumably why it is classified differently — and why the precheck passes.Environment and versions
--protocol quicproduces the identicalCRYPTO_ERROR 0x178.--protocol autowas not retested on 2026.8.3 — this is a production tunnel and each attempt takes the service down, so I did not want to run it again blind. Worth noting that on 2026.8.3 the precheck did, in a later run, correctly reportUDP Connectivity ... QUIC connection failedwithsuggested_protocol=http2, so the precheck behaviour may already differ between the two builds.Additional context
The network-side cause is almost certainly upstream of cloudflared and I am not asking you to fix it — QUIC from this uplink reaches Google, Facebook, Akamai and Vultr over HTTP/3 fine, but times out to Cloudflare (
104.18.0.0/16,1.1.1.0/24) and Fastly (151.101.0.0/16). Path MTU is 1500 to all of them.The report is only about the two client-side behaviours: the missing fallback, and a precheck that reports a path as healthy while that same path is failing in the same second.