{"record":{"id":"83277ec64a4022eb","repo":"tailscale/tailscale","slug":"could-not-enable-tcp-sack-v","errorCode":null,"errorMessage":"could not enable TCP SACK: %v","messagePattern":"could not enable TCP SACK: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"wgengine/netstack/netstack.go","lineNumber":360,"sourceCode":"\t\treturn nil, errors.New(\"nil logger\")\n\t}\n\tif e == nil {\n\t\treturn nil, errors.New(\"nil Engine\")\n\t}\n\tif pm == nil {\n\t\treturn nil, errors.New(\"nil proxymap.Mapper\")\n\t}\n\tif dialer == nil {\n\t\treturn nil, errors.New(\"nil Dialer\")\n\t}\n\tipstack := stack.New(stack.Options{\n\t\tNetworkProtocols:   []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},\n\t\tTransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol4, icmp.NewProtocol6},\n\t})\n\tsackEnabledOpt := tcpip.TCPSACKEnabled(true) // TCP SACK is disabled by default\n\ttcpipErr := ipstack.SetTransportProtocolOption(tcp.ProtocolNumber, &sackEnabledOpt)\n\tif tcpipErr != nil {\n\t\treturn nil, fmt.Errorf(\"could not enable TCP SACK: %v\", tcpipErr)\n\t}\n\t// See https://github.com/tailscale/tailscale/issues/9707\n\t// gVisor's RACK performs poorly. ACKs do not appear to be handled in a\n\t// timely manner, leading to spurious retransmissions and a reduced\n\t// congestion window.\n\ttcpRecoveryOpt := tcpip.TCPRecovery(0)\n\ttcpipErr = ipstack.SetTransportProtocolOption(tcp.ProtocolNumber, &tcpRecoveryOpt)\n\tif tcpipErr != nil {\n\t\treturn nil, fmt.Errorf(\"could not disable TCP RACK: %v\", tcpipErr)\n\t}\n\t// gVisor defaults to reno at the time of writing. We explicitly set reno\n\t// congestion control in order to prevent unexpected changes. Netstack\n\t// has an int overflow in sender congestion window arithmetic that is more\n\t// prone to trigger with cubic congestion control.\n\t// See https://github.com/google/gvisor/issues/11632\n\trenoOpt := tcpip.CongestionControlOption(\"reno\")\n\ttcpipErr = ipstack.SetTransportProtocolOption(tcp.ProtocolNumber, &renoOpt)\n\tif tcpipErr != nil {","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/tailscale/tailscale/blob/5201273aec737d6372ab7423c31c04ca3ca2a0c2/wgengine/netstack/netstack.go#L342-L378","documentation":"netstack.Create asked gVisor to enable TCP selective acknowledgement on the freshly created stack and gVisor returned an error. SACK is disabled by default in gVisor; failure here is unexpected and points at a gVisor API change.","triggerScenarios":"Thrown at wgengine/netstack/netstack.go:359 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check kernel support for TCP SACK; the wrapped error explains the rejection.","Update gVisor/netstack or the host kernel to a version supporting the SACK option."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}