ERROR

Troubleshooting Guide: HTTP/2 Connection Failures and GOAWAY Frames

Quick Fix Summary

TL;DR

Verify TLS ALPN negotiation and ensure both client and server send the correct HTTP/2 connection preface.

An HTTP/2 connection fails when the initial 'connection preface' (the string 'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n') is not correctly exchanged. The server responds with a GOAWAY frame to terminate the connection.

Diagnosis & Causes

  • Incorrect TLS ALPN extension during handshake.
  • Proxy or load balancer stripping/modifying the preface.
  • Client library bug sending malformed preface.
  • Server misconfiguration rejecting valid preface.
  • Network middlebox interfering with the initial data.
  • Recovery Steps

    1

    Step 1: Capture and Analyze the TLS Handshake

    Use OpenSSL's s_client to verify the Application-Layer Protocol Negotiation (ALPN) and inspect the raw connection preface.

    bash
    openssl s_client -alpn h2 -connect example.com:443 -servername example.com
    echo -ne "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" | openssl s_client -alpn h2 -connect example.com:443 -ign_eof
    2

    Step 2: Inspect Server Logs for GOAWAY Frames

    Check server application and access logs for HTTP/2-specific error codes. The GOAWAY frame includes a last-stream-id and error code.

    bash
    grep -i "GOAWAY\|PROTOCOL_ERROR\|HTTP_2" /var/log/nginx/error.log
    journalctl -u nginx --since "5 minutes ago" | grep -E "(err|h2)"
    3

    Step 3: Use a Packet Capture (tcpdump) to See the Preface

    Capture the first packets of the connection to see the exact bytes sent by the client and the server's GOAWAY response.

    bash
    sudo tcpdump -i any -s 0 -A 'host example.com and port 443' -w /tmp/h2_capture.pcap
    tcpdump -r /tmp/h2_capture.pcap -X -s 0 | head -50
    4

    Step 4: Verify Client Configuration and Libraries

    Ensure your HTTP client (curl, browser, application library) is configured for HTTP/2 and is using a compatible version.

    bash
    curl -v --http2 https://example.com
    # For Java/OkHttp: OkHttpClient client = new OkHttpClient.Builder().protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1)).build();
    5

    Step 5: Check for Interfering Proxies or Middleware

    Temporarily bypass any reverse proxies, WAFs, or API gateways to test a direct connection to the backend server.

    bash
    # Test direct to backend IP (if accessible)
    curl -v --http2 https://<backend-server-ip>:<port> --resolve example.com:443:<backend-server-ip>
    6

    Step 6: Configure Server for Strict HTTP/2 Compliance

    Explicitly set HTTP/2 directives and ensure no modules are interfering. Example for Nginx.

    nginx
    listen 443 ssl http2;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    Architect's Pro Tip

    "The GOAWAY frame's error code (found in logs/pcaps) is key. Code 0x1 (PROTOCOL_ERROR) often points directly to the malformed preface, while 0x7 (ENHANCE_YOUR_CALM) suggests load-related throttling."

    Frequently Asked Questions

    Can HTTP/1.1 and HTTP/2 connections cause this issue?

    Yes. If a client expecting HTTP/2 receives an HTTP/1.1 response (or vice versa) during the preface exchange, it will result in a PROTOCOL_ERROR and GOAWAY. This is often due to missing or incorrect ALPN.

    Is this error always caused by the client?

    No. While a malformed client preface is common, a misconfigured server, an interfering network device (like a proxy that doesn't fully support HTTP/2), or server-side throttling can also initiate the GOAWAY frame.

    Related HTTP Protocol Guides