{"record":{"id":"565fa25b1a3d7bbd","repo":"tailscale/tailscale","slug":"upload-failed-w","errorCode":null,"errorMessage":"upload failed: %w","messagePattern":"upload failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"net/speedtest/speedtest_server.go","lineNumber":115,"sourceCode":"\tfor {\n\t\tvar n int\n\t\tvar err error\n\n\t\tif conf.Direction == Download {\n\t\t\tn, err = io.ReadFull(conn, bufferData)\n\t\t\tswitch err {\n\t\t\tcase io.EOF, io.ErrUnexpectedEOF:\n\t\t\t\tbreak SpeedTestLoop\n\t\t\tcase nil:\n\t\t\t\t// successful read\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"unexpected error has occurred: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tn, err = conn.Write(bufferData)\n\t\t\tif err != nil {\n\t\t\t\t// If the write failed, there is most likely something wrong with the connection.\n\t\t\t\treturn nil, fmt.Errorf(\"upload failed: %w\", err)\n\t\t\t}\n\t\t}\n\t\tintervalBytes += n\n\n\t\tcurrentTime = time.Now()\n\t\t// checks if the current time is more or equal to the lastCalculated time plus the increment\n\t\tif currentTime.Sub(lastCalculated) >= increment {\n\t\t\tresults = append(results, Result{Bytes: intervalBytes, IntervalStart: lastCalculated, IntervalEnd: currentTime, Total: false})\n\t\t\tlastCalculated = currentTime\n\t\t\ttotalBytes += intervalBytes\n\t\t\tintervalBytes = 0\n\t\t}\n\n\t\tif conf.Direction == Upload && currentTime.Sub(startTime) > conf.TestDuration {\n\t\t\tbreak SpeedTestLoop\n\t\t}\n\t}\n","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/net/speedtest/speedtest_server.go#L97-L133","documentation":"In a server-side upload test (the client downloads), conn.Write failed, so the server could not push test data (net/speedtest/speedtest_server.go:111-116). The %w wraps the write error: broken pipe, connection reset, or i/o timeout — nearly always the client side hanging up early or the path breaking.","triggerScenarios":"Client disconnects or cancels before TestDuration elapses; receiver too slow so buffers fill and the connection stalls out; NAT state expiry dropping the flow.","commonSituations":"User closes the CLI mid-test; mobile client backgrounds the app; asymmetric MTU or NIC offload issues causing a stall on fast local links.","solutions":["Check whether the peer canceled (client-side context) before treating it as an infrastructure error","Retry the test; one-off resets are common","Run tailscale ping / check direct-vs-DERP status for the path","If reproducible on LAN, check MTU and hardware offload (GRO/GSO) on both NICs","Update both nodes to rule out old client bugs"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil { // server write path\n\tif errors.Is(err, net.ErrClosed) || errors.Is(err, context.Canceled) {\n\t\treturn err // deliberate shutdown: do not retry\n\t}\n\t// broken pipe / reset while uploading: safe to retry the whole test once\n}","preventionTips":["Keep the client connected for the full TestDuration","Cancel cleanly (context) rather than killing the process mid-test","Check MTU/NIC offload settings when writes fail reproducibly on LAN"],"tags":["speedtest","network","go","tailscale","connection-reset"],"backgroundTag":"connection-interrupted","analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}