{"record":{"id":"ba235a6a31ed8fe8","repo":"tailscale/tailscale","slug":"invalid-configuration-w","errorCode":null,"errorMessage":"invalid configuration: %w","messagePattern":"invalid configuration: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"cmd/containerboot/main.go","lineNumber":332,"sourceCode":"\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc main() {\n\tif err := run(); err != nil && !errors.Is(err, context.Canceled) {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc run() error {\n\tlog.SetPrefix(\"boot: \")\n\n\tcfg, err := configFromEnv()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid configuration: %w\", err)\n\t}\n\n\tif !cfg.UserspaceMode {\n\t\tif err := ensureTunFile(cfg.Root); err != nil {\n\t\t\treturn fmt.Errorf(\"unable to create tuntap device file: %w\", err)\n\t\t}\n\t\tif cfg.ProxyTargetIP != \"\" || cfg.ProxyTargetDNSName != \"\" || cfg.Routes != nil || cfg.TailnetTargetIP != \"\" || cfg.TailnetTargetFQDN != \"\" {\n\t\t\tif err := ensureIPForwarding(cfg.Root, cfg.ProxyTargetIP, cfg.TailnetTargetIP, cfg.TailnetTargetFQDN, cfg.Routes); err != nil {\n\t\t\t\tlog.Printf(\"Failed to enable IP forwarding: %v\", err)\n\t\t\t\tlog.Printf(\"To run tailscale as a proxy or router container, IP forwarding must be enabled.\")\n\t\t\t\tif cfg.InKubernetes {\n\t\t\t\t\treturn fmt.Errorf(\"you can either set the sysctls as a privileged initContainer, or run the tailscale container with privileged=true.\")\n\t\t\t\t} else {\n\t\t\t\t\treturn 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.\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/tailscale/tailscale/blob/cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042/cmd/containerboot/main.go#L314-L350","documentation":"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').","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the wrapped message — it names the exact variables in conflict; unset or fix those","For auth: keep exactly one mechanism (TS_AUTHKEY, or TS_CLIENT_ID+TS_CLIENT_SECRET, or TS_ID_TOKEN with TS_CLIENT_ID)","For proxies: either set TS_USERSPACE=false when using TS_DEST_IP/TS_TAILNET_TARGET_*, or drop the target vars","Validate POD_IPS is comma-separated with at most one IPv4 and one IPv6"],"exampleFix":"# before (conflicting auth + userspace proxy target)\nTS_AUTHKEY=tskey-...\nTS_CLIENT_ID=k1234\nTS_USERSPACE=true\nTS_DEST_IP=10.44.0.17\n\n# after (single auth mechanism; kernel mode for proxying)\nTS_AUTHKEY=tskey-...\nTS_USERSPACE=false\nTS_DEST_IP=10.44.0.17","handlingStrategy":"validation","validationCode":"// Dry-run the exact validation containerboot performs, in CI or an initContainer\nfunc validateEnv() error {\n\tauthkey := os.Getenv(\"TS_AUTHKEY\") != \"\"\n\tif authkey && (os.Getenv(\"TS_CLIENT_ID\") != \"\" || os.Getenv(\"TS_CLIENT_SECRET\") != \"\" || os.Getenv(\"TS_ID_TOKEN\") != \"\" || os.Getenv(\"TS_AUDIENCE\") != \"\") {\n\t\treturn errors.New(\"TS_AUTHKEY cannot be used with TS_CLIENT_ID, TS_CLIENT_SECRET, TS_ID_TOKEN, or TS_AUDIENCE\")\n\t}\n\tif def.Bool(os.Getenv(\"TS_USERSPACE\"), true) && os.Getenv(\"TS_DEST_IP\") != \"\" {\n\t\treturn errors.New(\"TS_DEST_IP is not supported with TS_USERSPACE\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"cfg, err := configFromEnv()\nif err != nil {\n\t// message names the exact conflicting env vars — fix env and restart; retrying without changes cannot succeed\n\treturn fmt.Errorf(\"invalid configuration: %w\", err)\n}","preventionTips":["Choose exactly one auth mechanism per deployment: authkey, OAuth client (TS_CLIENT_ID+TS_CLIENT_SECRET), or TS_ID_TOKEN","Automate env rendering through the operator/helm chart instead of hand-copying manifests so mutually exclusive vars never co-occur","Add a CI step that runs containerboot with your production env in a fake root and asserts it reaches startup"],"tags":["tailscale","kubernetes","configuration","env-vars","go"],"backgroundTag":null,"analyzedSha":"cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042","analyzedAt":"2026-08-15T19:58:31.583Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}