tailscale/tailscale · warning

feature not included in this build

Error message

feature not included in this build

What it means

Returned by the Tailscale localapi 'set-udp-gro-forwarding' endpoint when the binary was built without the GRO feature (buildfeatures.HasGRO == false), with HTTP 501 Not Implemented and feature.ErrUnavailable's message 'feature not included in this build'. The HasGRO build tag is only set for linux/amd64 and linux/arm64 builds; on all other platforms the endpoint is a stub.

Source

Thrown at ipn/localapi/localapi.go:825

	if !h.PermitRead {
		http.Error(w, "UDP GRO forwarding check access denied", http.StatusForbidden)
		return
	}
	var warning string
	if err := h.b.CheckUDPGROForwarding(); err != nil {
		warning = err.Error()
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(struct {
		Warning string
	}{
		Warning: warning,
	})
}

func (h *Handler) serveSetUDPGROForwarding(w http.ResponseWriter, r *http.Request) {
	if !buildfeatures.HasGRO {
		http.Error(w, feature.ErrUnavailable.Error(), http.StatusNotImplemented)
		return
	}
	if !h.PermitWrite {
		http.Error(w, "UDP GRO forwarding set access denied", http.StatusForbidden)
		return
	}
	var warning string
	if err := h.b.SetUDPGROForwarding(); err != nil {
		warning = err.Error()
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(struct {
		Warning string
	}{
		Warning: warning,
	})
}

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Treat HTTP 501 as a capability signal: probe and skip the call on platforms that lack GRO support
  2. Use a linux/amd64 or linux/arm64 build of tailscaled if you actually need to enable UDP GRO forwarding
  3. Gate the call on the platform: only invoke it on linux/amd64 and linux/arm64
  4. Update tailscaled to an official build for your platform so feature availability matches the client's expectations

Example fix

// before
if err := setUDPGROForwarding(ctx); err != nil { log.Fatal(err) }

// after
if runtime.GOOS == "linux" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64") {
    if err := setUDPGROForwarding(ctx); err != nil { log.Fatal(err) }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Probe capability before calling
if !(runtime.GOOS == "linux" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64")) {
    return nil // endpoint unsupported here
}

Type guard

func supportsGRO() bool {
    return runtime.GOOS == "linux" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64")
}

Try / catch

if resp.StatusCode == http.StatusNotImplemented {
    // feature absent in this build; skip silently
    return nil
}

Prevention

When it happens

Trigger: POST /localapi/v0/set-udp-gro-forwarding against a tailscaled built for a GOOS/GOARCH without the GRO tag (e.g. darwin, windows, linux/386, linux/arm), or a custom build that dropped the tag.

Common situations: Cross-compiled tailscaled running on an unusual architecture; older or minimal custom builds; clients that unconditionally call set-udp-gro-forwarding because the corresponding check endpoint existed and returned a warning; version drift where the client is newer than the daemon.

Related errors


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