{"record":{"id":"3e4049b741281f70","repo":"tailscale/tailscale","slug":"unsupported-gvisor-gsotype-v","errorCode":null,"errorMessage":"unsupported gVisor GSOType: %v","messagePattern":"unsupported gVisor GSOType: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"net/tstun/wrap.go","lineNumber":966,"sourceCode":"\tif !buildfeatures.HasNetstack {\n\t\tpanic(\"unreachable\")\n\t}\n\toptions := tun.GSOOptions{\n\t\tCsumStart:  gso.L3HdrLen,\n\t\tCsumOffset: gso.CsumOffset,\n\t\tGSOSize:    gso.MSS,\n\t\tNeedsCsum:  gso.NeedsCsum,\n\t}\n\tswitch gso.Type {\n\tcase netstack_GSONone:\n\t\toptions.GSOType = tun.GSONone\n\t\treturn options, nil\n\tcase netstack_GSOTCPv4:\n\t\toptions.GSOType = tun.GSOTCPv4\n\tcase netstack_GSOTCPv6:\n\t\toptions.GSOType = tun.GSOTCPv6\n\tdefault:\n\t\treturn tun.GSOOptions{}, fmt.Errorf(\"unsupported gVisor GSOType: %v\", gso.Type)\n\t}\n\t// options.HdrLen is both layer 3 and 4 together, whereas gVisor only\n\t// gives us layer 3 length. We have to gather TCP header length\n\t// ourselves.\n\tif len(pkt) < int(gso.L3HdrLen)+minTCPHeaderSize {\n\t\treturn tun.GSOOptions{}, errors.New(\"gVisor GSOTCP packet length too short\")\n\t}\n\ttcphLen := uint16(pkt[int(gso.L3HdrLen)+12] >> 4 * 4)\n\toptions.HdrLen = gso.L3HdrLen + tcphLen\n\treturn options, nil\n}\n\n// invertGSOChecksum inverts the transport layer checksum in pkt if gVisor\n// handed us a segment with a partial checksum. A partial checksum is not a\n// ones' complement of the sum, and incremental checksum updating is not yet\n// partial checksum aware. This may be called twice for a single packet,\n// both before and after partial checksum updates where later checksum\n// offloading still expects a partial checksum.","sourceCodeStart":948,"sourceCodeEnd":984,"githubUrl":"https://github.com/tailscale/tailscale/blob/5201273aec737d6372ab7423c31c04ca3ca2a0c2/net/tstun/wrap.go#L948-L984","documentation":"net/tstun converts gVisor netstack GSO metadata into wireguard-go tun.GSOOptions when moving packets toward the TUN device. Only GSONone, GSOTCPv4, and GSOTCPv6 have mappings; any other gVisor GSOType value falls to the default branch and yields this error. It signals a version skew between the vendored gVisor/netstack and wireguard-go tun packages (e.g. a new GSO type added upstream), not a runtime network condition.","triggerScenarios":"A packet arrives with gso.Type outside netstack_GSONone/GSOTCPv4/GSOTCPv6 — almost always after upgrading github.com/google/gvisor (or wireguard-go/wintun) independently of the versions Tailscale pins.","commonSituations":"go.mod upgrades of gvisor or wireguard-go in a fork/vendor tree; custom netstack builds that emit experimental UDP GSO types; cross-version mixing of tailscale components.","solutions":["Pin gvisor, netstack, and wireguard-go/wintun to the version pair the Tailscale release you track uses (check its go.mod)","If you intentionally added a GSO type in netstack, add the corresponding case mapping it to a tun.GSO* constant here","As a diagnostic, disable GSO on the affected path to confirm the version skew"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Guard is version alignment, checked at build time: keep gvisor,\n// wireguard-go and tailscale from the same release.\n// go.mod check example:\n//   require github.com/google/gvisor v0.0.0-<hash pinned by tailscale release>","typeGuard":null,"tryCatchPattern":"options, err := convertGSO(gso, pkt)\nif err != nil {\n\tif strings.Contains(err.Error(), \"unsupported gVisor GSOType\") {\n\t\t// version skew between netstack and tun — drop the packet and\n\t\t// alert; do not crash the data path\n\t\tlog.Printf(\"gso conversion failed (version skew?): %v\", err)\n\t\treturn tun.GSOOptions{}, nil // or drop packet upstream\n\t}\n\treturn tun.GSOOptions{}, err\n}","preventionTips":["Never bump gvisor or wireguard-go independently in a Tailscale fork; take them from the same release tag","Run the integration/test suite's throughput tests after any dep bump — GSO skew shows up immediately","If experimenting with new GSO types, add the mapping case in the same change"],"tags":["gvisor","netstack","gso","offload","tun","tailscale"],"backgroundTag":"unsupported-packet-offload-type","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"}