tailscale/tailscale · critical

invalid configuration: %w

Error message

invalid configuration: %w

What it means

containerboot's very first act is parsing its environment (configFromEnv); this wrap reports any validation failure before any networking starts, and main() turns it into log.Fatal — an immediate, permanent container exit. The message chain is precise: it names the exact conflicting variables (e.g. 'TS_AUTHKEY cannot be used with TS_CLIENT_ID...', 'TS_DEST_IP is not supported with TS_USERSPACE', 'POD_IPs can contain at most 2 IPs').

Source

Thrown at cmd/containerboot/main.go:332

					return
				}
			}
		}
	}
}

func main() {
	if err := run(); err != nil && !errors.Is(err, context.Canceled) {
		log.Fatal(err)
	}
}

func run() error {
	log.SetPrefix("boot: ")

	cfg, err := configFromEnv()
	if err != nil {
		return fmt.Errorf("invalid configuration: %w", err)
	}

	if !cfg.UserspaceMode {
		if err := ensureTunFile(cfg.Root); err != nil {
			return fmt.Errorf("unable to create tuntap device file: %w", err)
		}
		if cfg.ProxyTargetIP != "" || cfg.ProxyTargetDNSName != "" || cfg.Routes != nil || cfg.TailnetTargetIP != "" || cfg.TailnetTargetFQDN != "" {
			if err := ensureIPForwarding(cfg.Root, cfg.ProxyTargetIP, cfg.TailnetTargetIP, cfg.TailnetTargetFQDN, cfg.Routes); err != nil {
				log.Printf("Failed to enable IP forwarding: %v", err)
				log.Printf("To run tailscale as a proxy or router container, IP forwarding must be enabled.")
				if cfg.InKubernetes {
					return fmt.Errorf("you can either set the sysctls as a privileged initContainer, or run the tailscale container with privileged=true.")
				} else {
					return fmt.Errorf("you can fix this by running the container with privileged=true, or the equivalent in your container runtime that permits access to sysctls.")
				}
			}
		}
	}

View on GitHub (pinned to cfe32b8be6)

Solutions

  1. Read the wrapped message — it names the exact variables in conflict; unset or fix those
  2. For auth: keep exactly one mechanism (TS_AUTHKEY, or TS_CLIENT_ID+TS_CLIENT_SECRET, or TS_ID_TOKEN with TS_CLIENT_ID)
  3. For proxies: either set TS_USERSPACE=false when using TS_DEST_IP/TS_TAILNET_TARGET_*, or drop the target vars
  4. Validate POD_IPS is comma-separated with at most one IPv4 and one IPv6

Example fix

# before (conflicting auth + userspace proxy target)
TS_AUTHKEY=tskey-...
TS_CLIENT_ID=k1234
TS_USERSPACE=true
TS_DEST_IP=10.44.0.17

# after (single auth mechanism; kernel mode for proxying)
TS_AUTHKEY=tskey-...
TS_USERSPACE=false
TS_DEST_IP=10.44.0.17
Defensive patterns

Strategy: validation

Validate before calling

// Dry-run the exact validation containerboot performs, in CI or an initContainer
func validateEnv() error {
	authkey := os.Getenv("TS_AUTHKEY") != ""
	if authkey && (os.Getenv("TS_CLIENT_ID") != "" || os.Getenv("TS_CLIENT_SECRET") != "" || os.Getenv("TS_ID_TOKEN") != "" || os.Getenv("TS_AUDIENCE") != "") {
		return errors.New("TS_AUTHKEY cannot be used with TS_CLIENT_ID, TS_CLIENT_SECRET, TS_ID_TOKEN, or TS_AUDIENCE")
	}
	if def.Bool(os.Getenv("TS_USERSPACE"), true) && os.Getenv("TS_DEST_IP") != "" {
		return errors.New("TS_DEST_IP is not supported with TS_USERSPACE")
	}
	return nil
}

Try / catch

cfg, err := configFromEnv()
if err != nil {
	// message names the exact conflicting env vars — fix env and restart; retrying without changes cannot succeed
	return fmt.Errorf("invalid configuration: %w", err)
}

Prevention

When it happens

Trigger: Mutually exclusive auth envs set simultaneously (TS_AUTHKEY + TS_CLIENT_ID/SECRET/ID_TOKEN/AUDIENCE; TS_ID_TOKEN + TS_CLIENT_SECRET/AUDIENCE); proxy targets set with TS_USERSPACE=true (TS_DEST_IP, TS_TAILNET_TARGET_IP/FQDN); TS_DEST_IP together with TS_EXPERIMENTAL_DEST_DNS_NAME; POD_IPS containing >2 entries or an unparseable IP; EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS set in userspace mode, outside an ingress proxy, or without POD_IP.

Common situations: Helm chart values or Operator ProxyClass env changes that set both an authkey and OAuth vars; copying a sidecar manifest and leaving TS_DEST_IP while enabling userspace; deprecated TS_HEALTHCHECK_ADDR_PORT still set after 1.82; malformed POD_IPS from a custom admission webhook.

Related errors


AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15). Data as JSON: /api/errors/ba235a6a31ed8fe8. Report an issue: GitHub.