tailscale/tailscale · error

invalid tailscale handshake header

Error message

invalid tailscale handshake header

What it means

The client sent the expected Upgrade header but the base64 handshake header carrying the Noise initiation message could not be decoded. The server responds 400 and aborts. The request header value is malformed.

Source

Thrown at control/controlhttp/controlhttpserver/controlhttpserver.go:68

		http.Error(w, "missing next protocol", http.StatusBadRequest)
		return nil, errors.New("no next protocol in HTTP request")
	}
	if next == "websocket" {
		return acceptWebsocket(ctx, w, r, private)
	}
	if next != controlhttpcommon.UpgradeHeaderValue {
		http.Error(w, "unknown next protocol", http.StatusBadRequest)
		return nil, fmt.Errorf("client requested unhandled next protocol %q", next)
	}

	initB64 := r.Header.Get(controlhttpcommon.HandshakeHeaderName)
	if initB64 == "" {
		http.Error(w, "missing Tailscale handshake header", http.StatusBadRequest)
		return nil, errors.New("no tailscale handshake header in HTTP request")
	}
	init, err := base64.StdEncoding.DecodeString(initB64)
	if err != nil {
		http.Error(w, "invalid tailscale handshake header", http.StatusBadRequest)
		return nil, fmt.Errorf("decoding base64 handshake header: %v", err)
	}

	hijacker, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "make request over HTTP/1", http.StatusBadRequest)
		return nil, errors.New("can't hijack client connection")
	}

	w.Header().Set("Upgrade", controlhttpcommon.UpgradeHeaderValue)
	w.Header().Set("Connection", "upgrade")
	w.WriteHeader(http.StatusSwitchingProtocols)

	conn, brw, err := hijacker.Hijack()
	if err != nil {
		return nil, fmt.Errorf("hijacking client connection: %w", err)
	}

View on GitHub (pinned to 0fd2f14deb)

Solutions

  1. The handshake header is present but malformed; ensure the client is a genuine, up-to-date Tailscale client.
  2. Check for middleboxes altering header values in transit.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at control/controlhttp/controlhttpserver/controlhttpserver.go:62 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


AI-assisted analysis of tailscale/tailscale@0fd2f14deb (2026-08-18). Data as JSON: /api/errors/1c70411317ed13ff. Report an issue: GitHub.