{"record":{"id":"fdac74407d1caca8","repo":"tailscale/tailscale","slug":"failed-to-receive-w","errorCode":null,"errorMessage":"failed to receive: %w","messagePattern":"failed to receive: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"prober/derp.go","lineNumber":1015,"sourceCode":"\t// This goroutine reads packets from the `toc` DERP client and writes them towards the TUN.\n\t// It only reports errors to `recvErrC` channel.\n\twg.Add(1)\n\trecvErrC := make(chan error, 1)\n\tgo func() {\n\t\tdefer wg.Done()\n\n\t\t// Depending on platform, we need some space for headers at the front\n\t\t// of TUN I/O op buffers. The below constant is more than enough space\n\t\t// for any platform that this might run on.\n\t\ttunWriteStartOffset := device.MessageTransportHeaderSize\n\t\tbuf := make([]byte, mtu+tunWriteStartOffset)\n\t\tbufs := make([][]byte, 1)\n\n\t\tfromDERPPubKey := fromc.SelfPublicKey()\n\t\tfor {\n\t\t\tm, err := toc.Recv()\n\t\t\tif err != nil {\n\t\t\t\trecvErrC <- fmt.Errorf(\"failed to receive: %w\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tswitch v := m.(type) {\n\t\t\tcase derp.ReceivedPacket:\n\t\t\t\tif v.Source != fromDERPPubKey {\n\t\t\t\t\trecvErrC <- fmt.Errorf(\"got data packet from unexpected source, %v\", v.Source)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tpkt := v.Data\n\t\t\t\tcopy(buf[tunWriteStartOffset:], pkt)\n\t\t\t\tbufs[0] = buf[:len(pkt)+tunWriteStartOffset]\n\t\t\t\tif _, err := dev.Write(bufs, tunWriteStartOffset); err != nil {\n\t\t\t\t\trecvErrC <- fmt.Errorf(\"failed to write to TUN device: %w\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase derp.KeepAliveMessage:\n\t\t\t\t// Silently ignore.\n\t\t\tdefault:","sourceCodeStart":997,"sourceCodeEnd":1033,"githubUrl":"https://github.com/tailscale/tailscale/blob/5201273aec737d6372ab7423c31c04ca3ca2a0c2/prober/derp.go#L997-L1033","documentation":"In the TUN bandwidth probe, a goroutine loops on toc.Recv() to pull packets relayed back over the 'to' DERP connection and inject them into the TUN device. This error fires when Recv itself fails — the receiving DERP stream broke mid-transfer (the TUN-mode analogue of the pair probe's receive error).","triggerScenarios":"toc.Recv() returns an error: the derper closed or reset the client connection, a TLS stream failure, a protocol error frame, or the client was closed locally by the probe teardown path.","commonSituations":"Receiving derper restarting during a long bandwidth transfer; LB/proxy idle or request timeouts cutting the long-lived HTTPS stream; server evicting the client; very large transfer sizes stretching the connection past intermediary limits.","solutions":["Inspect the wrapped error for EOF/ECONNRESET/TLS causes to distinguish a drop from a protocol failure.","Re-run with a smaller transfer size: if small transfers pass, an intermediary idle timeout is truncating long streams.","Check the 'to' derper's logs and connection limits for the failure window.","For probes behind proxies, raise idle timeouts or exclude DERP traffic from the proxy."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if err := toc.Connect(ctx); err != nil {\n    return fmt.Errorf(\"to client not connected: %w\", err)\n}","typeGuard":"func isConnDropped(err error) bool {\n    return errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) ||\n        errors.Is(err, syscall.ECONNRESET)\n}","tryCatchPattern":"Classify the wrapped cause: EOF/ECONNRESET -> drop, recreate clients and retry once; TLS error -> investigate certs; persistent for long transfers only -> shrink size or raise intermediary idle timeouts instead of retrying.","preventionTips":["Keep bandwidth transfer durations under intermediary idle timeouts","Ensure derper and any LB in front of it permit long-lived connections","Recreate DERP clients per probe run","Monitor the 'to' node's connection-reset counters during sustained probing"],"tags":["derp","recv","connection-reset","tun-probe","go"],"backgroundTag":"connection-read-error","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"}