{"record":{"id":"861531dbcb390b32","repo":"tailscale/tailscale","slug":"fetch-control-key-response-v","errorCode":null,"errorMessage":"fetch control key response: %v","messagePattern":"fetch control key response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"control/controlclient/direct.go","lineNumber":1498,"sourceCode":"\treturn nil\n}\n\n// encode JSON encodes v as JSON, logging tailcfg.MapRequest values if\n// debugMap is set.\nfunc encode(v any) ([]byte, error) {\n\tb, err := json.Marshal(v)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif DevKnob.DumpNetMaps() {\n\t\tif _, ok := v.(*tailcfg.MapRequest); ok {\n\t\t\tlog.Printf(\"MapRequest: %s\", b)\n\t\t}\n\t}\n\treturn b, nil\n}\n\nfunc loadServerPubKeys(ctx context.Context, httpc *http.Client, serverURL string) (*tailcfg.OverTLSPublicKeyResponse, error) {\n\tkeyURL := fmt.Sprintf(\"%v/key?v=%d\", serverURL, tailcfg.CurrentCapabilityVersion)\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", keyURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create control key request: %v\", err)\n\t}\n\tres, err := httpc.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fetch control key: %v\", err)\n\t}\n\tdefer res.Body.Close()\n\tb, err := io.ReadAll(io.LimitReader(res.Body, 64<<10))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fetch control key response: %v\", err)\n\t}\n\tif res.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"fetch control key: %v\", res.Status)\n\t}\n\tvar out tailcfg.OverTLSPublicKeyResponse","sourceCodeStart":1480,"sourceCodeEnd":1516,"githubUrl":"https://github.com/tailscale/tailscale/blob/5201273aec737d6372ab7423c31c04ca3ca2a0c2/control/controlclient/direct.go#L1480-L1516","documentation":"The response headers for GET /key arrived, but reading the body with io.ReadAll(io.LimitReader(res.Body, 64<<10)) failed. The connection dropped between headers and body completion (read error, reset, timeout).","triggerScenarios":"Connection reset mid-body by a proxy or load balancer, read timeout expiring while streaming the key response, or a TLS error surfacing during body read.","commonSituations":"Flaky networks (Wi-Fi/VPN transitions), proxies that close connections early after headers, servers that close keep-alive connections abruptly.","solutions":["Retry the operation; transient mid-body failures usually succeed on a fresh connection","Check for MTU or VPN tunnel issues if it recurs","Reproduce with curl to see whether the server consistently truncates the /key response"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var netErr net.Error\nif errors.As(err, &netErr) {\n    // transient read failure: retry on a fresh connection with backoff\n}","preventionTips":["Treat mid-body read errors as transient by default","Use reasonable per-request timeouts so stuck body reads surface fast"],"tags":["network","http-body","control-plane","tailscale"],"backgroundTag":"connection-reset","analyzedSha":"5201273aec737d6372ab7423c31c04ca3ca2a0c2","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}