{"record":{"id":"1b89c37439a96dff","repo":"tailscale/tailscale","slug":"derp-client-failed-to-receive-server-key-v","errorCode":null,"errorMessage":"derp.Client: failed to receive server key: %v","messagePattern":"derp\\.Client: failed to receive server key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"derp/derp_client.go","lineNumber":144,"sourceCode":"}\n\nfunc newClient(privateKey key.NodePrivate, nc Conn, brw *bufio.ReadWriter, logf logger.Logf, opt clientOpt) (*Client, error) {\n\tc := &Client{\n\t\tprivateKey:  privateKey,\n\t\tpublicKey:   privateKey.Public(),\n\t\tlogf:        logf,\n\t\tnc:          nc,\n\t\tbr:          brw.Reader,\n\t\tbw:          brw.Writer,\n\t\tmeshKey:     opt.MeshKey,\n\t\tcanAckPings: opt.CanAckPings,\n\t\tisProber:    opt.IsProber,\n\t\tappName:     opt.AppName,\n\t\tclock:       tstime.StdClock{},\n\t}\n\tif opt.ServerPub.IsZero() {\n\t\tif err := c.recvServerKey(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"derp.Client: failed to receive server key: %v\", err)\n\t\t}\n\t} else {\n\t\tc.serverKey = opt.ServerPub\n\t}\n\tif err := c.sendClientKey(); err != nil {\n\t\treturn nil, fmt.Errorf(\"derp.Client: failed to send client key: %v\", err)\n\t}\n\treturn c, nil\n}\n\nfunc (c *Client) PublicKey() key.NodePublic { return c.publicKey }\n\nfunc (c *Client) recvServerKey() error {\n\tvar buf [40]byte\n\tt, flen, err := readFrame(c.br, 1<<10, buf[:])\n\tif err == io.ErrShortBuffer {\n\t\t// For future-proofing, allow server to send more in its greeting.\n\t\terr = nil","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/tailscale/tailscale/blob/a7769cbc33a3eba62bb16fc803b97077c2969d16/derp/derp_client.go#L126-L162","documentation":"derp.NewClient could not receive and validate the server's greeting (server key frame) before sending the client key: recvServerKey failed on read, frame type, greeting magic, or key length. The connection never got past its first frame, so it is unusable.","triggerScenarios":"The remote is not a DERP server (for example it returns an HTTP error page); the connection drops immediately after accept; the greeting frame is malformed; TLS interception mangles the bytes.","commonSituations":"Wrong address or port; DERP server behind a broken proxy; server crashing on accept.","solutions":["Probe the endpoint: curl https://host/derp/probe should return \"derp\"","Check server-side logs for the accepted-then-failed connection","Remove middleboxes and verify TLS configuration"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"resp, err := http.Get(derpBase + \"/derp/probe\")\nif err != nil {\n    return err\n}\ndefer resp.Body.Close()\nb, _ := io.ReadAll(resp.Body)\nif resp.StatusCode != 200 || strings.TrimSpace(string(b)) != \"derp\" {\n    return fmt.Errorf(\"%s is not a DERP server\", derpBase)\n}","typeGuard":null,"tryCatchPattern":"c, err := derp.NewClient(conn, key, opts)\nif err != nil && strings.Contains(err.Error(), \"failed to receive server key\") {\n    // greeting failed: often transient or wrong endpoint; re-dial with backoff\n    c, err = redialWithBackoff(conn, key, opts)\n}","preventionTips":["Validate DERP endpoints with /derp/probe before connecting","Verify TLS certificates and ports; keep proxies from altering the byte stream"],"tags":["go","derp","handshake","connection","network"],"backgroundTag":"connection-handshake-failed","analyzedSha":"a7769cbc33a3eba62bb16fc803b97077c2969d16","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}