kubernetes/kops · error

building kubernetes client for node labeler: %w

Error message

building kubernetes client for node labeler: %w

What it means

runApplyChannelIteration wraps any failure from f.KubernetesClient() with this message when --node-name is set, before node labels can be bootstrapped. The underlying error comes from constructing a clientset from the REST config (bad kubeconfig, unreachable apiserver, TLS problems). It is accumulated into a multierr alongside any channel-apply failure.

Source

Thrown at channels/pkg/cmd/apply_channel.go:109

			return nil, fmt.Errorf("Error too many '=' (%d) in %s", len(pair), pair)
		} else if len(pair) == 2 {
			labels[pair[0]] = pair[1]
		} else {
			labels[rawpair] = ""
		}
	}
	return labels, nil
}

// runApplyChannelIteration patches node labels (when --node-name is set) then
// applies the channel. Labels go first so addons targeting the control-plane
// label can schedule on the local node as soon as their manifests land.
func runApplyChannelIteration(ctx context.Context, f *ChannelsFactory, out io.Writer, options *ApplyChannelOptions, args []string) error {
	var merr error
	if options.NodeName != "" {
		labelerClient, err := f.KubernetesClient()
		if err != nil {
			merr = multierr.Append(merr, fmt.Errorf("building kubernetes client for node labeler: %w", err))
		} else if err := nodelabeler.BootstrapControlPlaneNodeLabels(ctx, labelerClient, options.NodeName, options.NodeLabels); err != nil {
			merr = multierr.Append(merr, fmt.Errorf("bootstrapping node labels: %w", err))
		}
	}
	if err := RunApplyChannel(ctx, f, out, options, args); err != nil {
		merr = multierr.Append(merr, err)
	}
	return merr
}

// runApplyChannelLoop reconciles repeatedly until ctx is cancelled. A fresh
// ChannelsFactory per iteration drops cached REST configs and the discovery
// cache, picking up cert rotation and new CRDs without a restart.
func runApplyChannelLoop(ctx context.Context, out io.Writer, options *ApplyChannelOptions, args []string) error {
	// In daemon mode kops-channels runs as a system-node-critical static pod; serve a
	// readiness probe reporting the last apply outcome, so a persistent failure surfaces
	// as NotReady (failing `kops validate cluster`, which gates rolling updates) instead
	// of only being logged. Starts NotReady until the first successful apply.

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Ensure the kubeconfig or in-cluster service account is present and valid (KUBECONFIG, /var/run/secrets/kubernetes.io/serviceaccount)
  2. Run `kubectl version` with the same config to confirm the client can reach the cluster
  3. If in a pod, verify the service account token and KUBERNETES_SERVICE_HOST/PORT env are set
  4. Inspect the wrapped inner error for the exact config problem

Example fix

// before (no config found)
kops channels --node-name ip-10-0-0-5
// after
KUBECONFIG=/etc/kubernetes/admin.conf kops channels --node-name ip-10-0-0-5
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: verify client construction before calling
if _, err := f.KubernetesClient(); err != nil {
	return fmt.Errorf("precheck: kubernetes client unavailable: %w", err)
}

Try / catch

err := runApplyChannelIteration(ctx, f, out, options, args)
if err != nil && strings.Contains(err.Error(), "building kubernetes client for node labeler") {
	// inspect wrapped cause with errors.Unwrap / %v inner error
	klog.Errorf("client init failed, check kubeconfig/in-cluster config: %v", err)
}

Prevention

When it happens

Trigger: `kops channels --node-name <node>` where the Kubernetes client cannot be built: in-cluster config unavailable (not running in a pod, missing KUBERNETES_SERVICE_HOST), invalid or missing kubeconfig, or malformed REST config from the factory.

Common situations: Running the binary locally without a kubeconfig when it expects in-cluster config; a static pod missing service-account mounts; KUBECONFIG pointing at a deleted context; registry/auth plugin errors.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/d021f58df30ffae8. Report an issue: GitHub.