tailscale/tailscale · error

derp.Client: failed to receive server key: %v

Error message

derp.Client: failed to receive server key: %v

What it means

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.

Source

Thrown at derp/derp_client.go:144

}

func newClient(privateKey key.NodePrivate, nc Conn, brw *bufio.ReadWriter, logf logger.Logf, opt clientOpt) (*Client, error) {
	c := &Client{
		privateKey:  privateKey,
		publicKey:   privateKey.Public(),
		logf:        logf,
		nc:          nc,
		br:          brw.Reader,
		bw:          brw.Writer,
		meshKey:     opt.MeshKey,
		canAckPings: opt.CanAckPings,
		isProber:    opt.IsProber,
		appName:     opt.AppName,
		clock:       tstime.StdClock{},
	}
	if opt.ServerPub.IsZero() {
		if err := c.recvServerKey(); err != nil {
			return nil, fmt.Errorf("derp.Client: failed to receive server key: %v", err)
		}
	} else {
		c.serverKey = opt.ServerPub
	}
	if err := c.sendClientKey(); err != nil {
		return nil, fmt.Errorf("derp.Client: failed to send client key: %v", err)
	}
	return c, nil
}

func (c *Client) PublicKey() key.NodePublic { return c.publicKey }

func (c *Client) recvServerKey() error {
	var buf [40]byte
	t, flen, err := readFrame(c.br, 1<<10, buf[:])
	if err == io.ErrShortBuffer {
		// For future-proofing, allow server to send more in its greeting.
		err = nil

View on GitHub (pinned to a7769cbc33)

Solutions

  1. Probe the endpoint: curl https://host/derp/probe should return "derp"
  2. Check server-side logs for the accepted-then-failed connection
  3. Remove middleboxes and verify TLS configuration
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Get(derpBase + "/derp/probe")
if err != nil {
    return err
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
if resp.StatusCode != 200 || strings.TrimSpace(string(b)) != "derp" {
    return fmt.Errorf("%s is not a DERP server", derpBase)
}

Try / catch

c, err := derp.NewClient(conn, key, opts)
if err != nil && strings.Contains(err.Error(), "failed to receive server key") {
    // greeting failed: often transient or wrong endpoint; re-dial with backoff
    c, err = redialWithBackoff(conn, key, opts)
}

Prevention

When it happens

Trigger: 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.

Common situations: Wrong address or port; DERP server behind a broken proxy; server crashing on accept.

Related errors


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