tailscale/tailscale · error

upload failed: %w

Error message

upload failed: %w

What it means

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.

Source

Thrown at net/speedtest/speedtest_server.go:115

	for {
		var n int
		var err error

		if conf.Direction == Download {
			n, err = io.ReadFull(conn, bufferData)
			switch err {
			case io.EOF, io.ErrUnexpectedEOF:
				break SpeedTestLoop
			case nil:
				// successful read
			default:
				return nil, fmt.Errorf("unexpected error has occurred: %w", err)
			}
		} else {
			n, err = conn.Write(bufferData)
			if err != nil {
				// If the write failed, there is most likely something wrong with the connection.
				return nil, fmt.Errorf("upload failed: %w", err)
			}
		}
		intervalBytes += n

		currentTime = time.Now()
		// checks if the current time is more or equal to the lastCalculated time plus the increment
		if currentTime.Sub(lastCalculated) >= increment {
			results = append(results, Result{Bytes: intervalBytes, IntervalStart: lastCalculated, IntervalEnd: currentTime, Total: false})
			lastCalculated = currentTime
			totalBytes += intervalBytes
			intervalBytes = 0
		}

		if conf.Direction == Upload && currentTime.Sub(startTime) > conf.TestDuration {
			break SpeedTestLoop
		}
	}

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Check whether the peer canceled (client-side context) before treating it as an infrastructure error
  2. Retry the test; one-off resets are common
  3. Run tailscale ping / check direct-vs-DERP status for the path
  4. If reproducible on LAN, check MTU and hardware offload (GRO/GSO) on both NICs
  5. Update both nodes to rule out old client bugs
Defensive patterns

Strategy: retry

Try / catch

if err != nil { // server write path
	if errors.Is(err, net.ErrClosed) || errors.Is(err, context.Canceled) {
		return err // deliberate shutdown: do not retry
	}
	// broken pipe / reset while uploading: safe to retry the whole test once
}

Prevention

When it happens

Trigger: Client disconnects or cancels before TestDuration elapses; receiver too slow so buffers fill and the connection stalls out; NAT state expiry dropping the flow.

Common situations: User closes the CLI mid-test; mobile client backgrounds the app; asymmetric MTU or NIC offload issues causing a stall on fast local links.

Related errors


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/565fa25b1a3d7bbd. Report an issue: GitHub.