tailscale/tailscale · error

storing device IPs and FQDN in Kubernetes Secret: %w

Error message

storing device IPs and FQDN in Kubernetes Secret: %w

What it means

After routing rules are successfully installed, operator-managed proxies patch the node's FQDN and tailnet IPs into 'device_fqdn'/'device_ips' of the state Secret (storeDeviceEndpoints, kube.go:76 -> StrategicMergePatchSecret). The operator reads these to publish proxy endpoints (e.g. on Ingress status) and treats them as a readiness signal, so any Kubernetes API failure here is fatal to containerboot.

Source

Thrown at cmd/containerboot/main.go:893

				}
			}
			currentIPs = newCurrentIPs

			// Only store device FQDN and IP addresses to
			// Kubernetes Secret when any required proxy
			// route setup has succeeded. IPs and FQDN are
			// read from the Secret by the Tailscale
			// Kubernetes operator and, for some proxy
			// types, such as Tailscale Ingress, advertized
			// on the Ingress status. Writing them to the
			// Secret only after the proxy routing has been
			// set up ensures that the operator does not
			// advertize endpoints of broken proxies.
			// TODO (irbekrm): instead of using the IP and FQDN, have some other mechanism for the proxy signal that it is 'Ready'.
			deviceEndpoints := []any{self.Name(), self.Addresses()}
			if hasKubeStateStore(cfg) && deephash.Update(&currentDeviceEndpoints, &deviceEndpoints) {
				if err := kc.storeDeviceEndpoints(ctx, self.Name(), addrs); err != nil {
					return fmt.Errorf("storing device IPs and FQDN in Kubernetes Secret: %w", err)
				}
			}

			if healthCheck != nil {
				healthCheck.Update(len(addrs) != 0)
			}

			var prevServeConfig *ipn.ServeConfig
			if getAutoAdvertiseBool() {
				prevServeConfig, err = client.GetServeConfig(ctx)
				if err != nil {
					return fmt.Errorf("autoadvertisement: failed to get serve config: %w", err)
				}

				err = refreshAdvertiseServices(ctx, prevServeConfig, klc.New(client))
				if err != nil {
					return fmt.Errorf("autoadvertisement: failed to refresh advertise services: %w", err)
				}

View on GitHub (pinned to cfe32b8be6)

Solutions

  1. Verify the Secret exists: kubectl get secret <name>
  2. Verify RBAC: kubectl auth can-i patch secret <name> as the pod's ServiceAccount
  3. Check apiserver connectivity and any admission webhook rejecting the patch
  4. Recreate the proxy resource so the operator rebuilds state
Defensive patterns

Strategy: validation

Validate before calling

# readiness of the state store before endpoints are published
kubectl get secret "$STATE_SECRET" -o name >/dev/null || echo "state Secret missing"
kubectl auth can-i patch secret "$STATE_SECRET" >/dev/null || echo "no patch permission"

Prevention

When it happens

Trigger: State Secret deleted or renamed; ServiceAccount lacking get/patch on secrets; kube-apiserver unreachable; patch rejected with 409/422; expired SA tokens.

Common situations: Manual deletion of the state Secret while proxies run; missing Role bindings in custom operator installs; API server outages; strict namespace quotas or validating webhooks rejecting the patch.

Related errors


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