tailscale/tailscale · error
TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS is not suppo
Error message
TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS is not supported in userspace mode
What it means
containerboot rejects the combination of TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS=true with userspace networking mode. The forwarding optimizations install kernel-level forwarding rules (iptables/netfilter fast paths) that only exist when tailscaled owns a kernel network stack; in userspace mode (TS_USERSPACE=true, the default at settings.go:109) there is no kernel stack to optimize, so settings validation fails fast instead of silently doing nothing.
Source
Thrown at cmd/containerboot/settings.go:325
return errors.New("TS_ID_TOKEN and TS_AUDIENCE cannot both be set")
}
if s.Audience != "" && s.ClientSecret != "" {
return errors.New("TS_AUDIENCE and TS_CLIENT_SECRET cannot both be set")
}
if s.AuthKey != "" && (s.ClientID != "" || s.ClientSecret != "" || s.IDToken != "" || s.Audience != "") {
return errors.New("TS_AUTHKEY cannot be used with TS_CLIENT_ID, TS_CLIENT_SECRET, TS_ID_TOKEN, or TS_AUDIENCE.")
}
if s.AllowProxyingClusterTrafficViaIngress && s.UserspaceMode {
return errors.New("EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is not supported in userspace mode")
}
if s.AllowProxyingClusterTrafficViaIngress && s.ServeConfigPath == "" {
return errors.New("EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is set but this is not a cluster ingress proxy")
}
if s.AllowProxyingClusterTrafficViaIngress && s.PodIP == "" {
return errors.New("EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS is set but POD_IP is not set")
}
if s.EnableForwardingOptimizations && s.UserspaceMode {
return errors.New("TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS is not supported in userspace mode")
}
if s.HealthCheckAddrPort != "" {
log.Printf("[warning] TS_HEALTHCHECK_ADDR_PORT is deprecated and will be removed in 1.82.0. Please use TS_ENABLE_HEALTH_CHECK and optionally TS_LOCAL_ADDR_PORT instead.")
if _, err := netip.ParseAddrPort(s.HealthCheckAddrPort); err != nil {
return fmt.Errorf("error parsing TS_HEALTHCHECK_ADDR_PORT value %q: %w", s.HealthCheckAddrPort, err)
}
}
if s.localMetricsEnabled() || s.localHealthEnabled() || s.EgressProxiesCfgPath != "" {
if _, err := netip.ParseAddrPort(s.LocalAddrPort); err != nil {
return fmt.Errorf("error parsing TS_LOCAL_ADDR_PORT value %q: %w", s.LocalAddrPort, err)
}
}
if s.DebugAddrPort != "" {
if _, err := netip.ParseAddrPort(s.DebugAddrPort); err != nil {
return fmt.Errorf("error parsing TS_DEBUG_ADDR_PORT value %q: %w", s.DebugAddrPort, err)
}
}
if s.HealthCheckEnabled && s.HealthCheckAddrPort != "" {View on GitHub (pinned to cfe32b8be6)
Solutions
- Set TS_USERSPACE=false in the container env — this requires the container to have /dev/net/tun and the NET_ADMIN capability
- If the workload must stay in userspace mode (e.g. no TUN device), unset TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS
- Audit the Helm values / manifest for stale defaults that set TS_USERSPACE=true
Example fix
# before
env:
- name: TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS
value: 'true'
- name: TS_USERSPACE
value: 'true'
# after
env:
- name: TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS
value: 'true'
- name: TS_USERSPACE
value: 'false'
# plus: /dev/net/tun device and NET_ADMIN capability on the container Defensive patterns
Strategy: validation
Validate before calling
#!/usr/bin/env bash
set -euo pipefail
userspace="${TS_USERSPACE:-true}"
fwd="${TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS:-false}"
if [[ "$fwd" == "true" && "$userspace" == "true" ]]; then
echo 'TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS requires TS_USERSPACE=false' >&2
exit 1
fi Prevention
- Remember TS_USERSPACE defaults to true — never assume unset means kernel mode
- When enabling forwarding optimizations, always set TS_USERSPACE=false explicitly in the same change
- Pair kernel mode with the required device/capability checks (dev/net/tun, NET_ADMIN) in CI manifest tests
When it happens
Trigger: TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS set to true (default false, settings.go:129) AND TS_USERSPACE unset (defaults true) or explicitly set to true, in the same container.
Common situations: Enabling subnet-router/forwarding optimizations on a proxy pod without also switching it out of the default userspace mode; Helm charts or examples that keep TS_USERSPACE defaulting to true; upgrading a config where userspace mode was previously disabled elsewhere.
Related errors
- TS_DEST_IP is not supported with TS_USERSPACE
- TS_EXPERIMENTAL_DEST_DNS_NAME is not supported with TS_USERS
- TS_EXPERIMENTAL_DEST_DNS_NAME and TS_DEST_IP cannot both be
- TS_TAILNET_TARGET_IP is not supported with TS_USERSPACE
- TS_TAILNET_TARGET_FQDN is not supported with TS_USERSPACE
AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15).
Data as JSON: /api/errors/5afcb38444f8623f.
Report an issue: GitHub.