{"record":{"id":"1c70411317ed13ff","repo":"tailscale/tailscale","slug":"invalid-tailscale-handshake-header","errorCode":null,"errorMessage":"invalid tailscale handshake header","messagePattern":"invalid tailscale handshake header","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"control/controlhttp/controlhttpserver/controlhttpserver.go","lineNumber":68,"sourceCode":"\t\thttp.Error(w, \"missing next protocol\", http.StatusBadRequest)\n\t\treturn nil, errors.New(\"no next protocol in HTTP request\")\n\t}\n\tif next == \"websocket\" {\n\t\treturn acceptWebsocket(ctx, w, r, private)\n\t}\n\tif next != controlhttpcommon.UpgradeHeaderValue {\n\t\thttp.Error(w, \"unknown next protocol\", http.StatusBadRequest)\n\t\treturn nil, fmt.Errorf(\"client requested unhandled next protocol %q\", next)\n\t}\n\n\tinitB64 := r.Header.Get(controlhttpcommon.HandshakeHeaderName)\n\tif initB64 == \"\" {\n\t\thttp.Error(w, \"missing Tailscale handshake header\", http.StatusBadRequest)\n\t\treturn nil, errors.New(\"no tailscale handshake header in HTTP request\")\n\t}\n\tinit, err := base64.StdEncoding.DecodeString(initB64)\n\tif err != nil {\n\t\thttp.Error(w, \"invalid tailscale handshake header\", http.StatusBadRequest)\n\t\treturn nil, fmt.Errorf(\"decoding base64 handshake header: %v\", err)\n\t}\n\n\thijacker, ok := w.(http.Hijacker)\n\tif !ok {\n\t\thttp.Error(w, \"make request over HTTP/1\", http.StatusBadRequest)\n\t\treturn nil, errors.New(\"can't hijack client connection\")\n\t}\n\n\tw.Header().Set(\"Upgrade\", controlhttpcommon.UpgradeHeaderValue)\n\tw.Header().Set(\"Connection\", \"upgrade\")\n\tw.WriteHeader(http.StatusSwitchingProtocols)\n\n\tconn, brw, err := hijacker.Hijack()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"hijacking client connection: %w\", err)\n\t}\n","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/tailscale/tailscale/blob/0fd2f14deb478d09c95f38af2b0d35b492b63520/control/controlhttp/controlhttpserver/controlhttpserver.go#L50-L86","documentation":"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.","triggerScenarios":"Thrown at control/controlhttp/controlhttpserver/controlhttpserver.go:62 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The handshake header is present but malformed; ensure the client is a genuine, up-to-date Tailscale client.","Check for middleboxes altering header values in transit."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"0fd2f14deb478d09c95f38af2b0d35b492b63520","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}