kubernetes/kops · error

parsing kops-channels manifest: %w

Error message

parsing kops-channels manifest: %w

What it means

rewriteChannelsManifestForEnroll unmarshals the embedded kops-channels static pod manifest into a corev1.Pod before rewriting the bootstrap-channel URL to a local file:// path. This error wraps the YAML unmarshal failure, meaning the byte slice passed in was not parseable as a Kubernetes Pod manifest. It guards the rest of the rewrite logic (container arg rewriting and hostPath mounting) from operating on garbage data.

Source

Thrown at pkg/commands/toolbox_enroll.go:1013

		return nil, err
	}
	bootstrapData.NodeupScript = nodeupScriptBytes
	bootstrapData.NodeupConfig = nodeupConfig

	b.bootstrapData = bootstrapData

	return bootstrapData, nil
}

// rewriteChannelsManifestForEnroll rewrites the bootstrap-channel URL in the kops-channels
// pod's container args to a file:// URL under localAddonsDir, and adds the matching hostPath
// mount so the container can read the bootstrap from the host. Custom addons pass through
// unchanged. If no arg matches the bootstrap URL we warn — the cloudup manifest shape almost
// certainly drifted and the enrolled node won't be able to reach the bootstrap channel.
func rewriteChannelsManifestForEnroll(data []byte, bootstrapChannelURL string, localAddonsDir string) ([]byte, error) {
	pod := &corev1.Pod{}
	if err := yaml.Unmarshal(data, pod); err != nil {
		return nil, fmt.Errorf("parsing kops-channels manifest: %w", err)
	}
	localBootstrap := "file://" + path.Join(localAddonsDir, "bootstrap-channel.yaml")
	rewroteContainer := -1
	for ci := range pod.Spec.Containers {
		args := pod.Spec.Containers[ci].Args
		for i, arg := range args {
			if arg == bootstrapChannelURL {
				args[i] = localBootstrap
				rewroteContainer = ci
			}
		}
	}
	if rewroteContainer < 0 {
		klog.Warningf("kops-channels manifest had no arg matching the bootstrap URL %q; enrolled node will not be able to reach the bootstrap channel", bootstrapChannelURL)
		return k8scodecs.ToVersionedYaml(pod)
	}
	kubemanifest.AddHostPathMapping(pod, &pod.Spec.Containers[rewroteContainer], "channels-enroll", localAddonsDir,
		kubemanifest.WithType(corev1.HostPathDirectory))

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Inspect the wrapped inner error (%w) to find the exact YAML/decode failure line or type mismatch
  2. Dump the input bytes and validate them with `kubectl apply --dry-run=client -f -` or sigs.k8s.io/yaml.Unmarshal into corev1.Pod yourself
  3. Verify the manifest embedded/produced by cloudup matches the current kOps version; rebuild or re-extract the manifest if it was customized
  4. Ensure the manifest is a full Pod object (apiVersion: v1, kind: Pod) rather than a fragment such as a bare container spec

Example fix

// before
pod := &corev1.Pod{}
if err := yaml.Unmarshal(data, pod); err != nil {
	return nil, fmt.Errorf("parsing kops-channels manifest: %w", err)
}
// after
var raw map[string]interface{}
if err := yaml.Unmarshal(data, &raw); err != nil {
	return nil, fmt.Errorf("parsing kops-channels manifest: not valid YAML: %w", err)
}
if k, _ := raw["kind"].(string); k != "Pod" {
	return nil, fmt.Errorf("parsing kops-channels manifest: got kind %q, want Pod", k)
}
pod := &corev1.Pod{}
if err := yaml.Unmarshal(data, pod); err != nil {
	return nil, fmt.Errorf("parsing kops-channels manifest: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

func isValidPodManifest(data []byte) bool {
	pod := &corev1.Pod{}
	return yaml.Unmarshal(data, pod) == nil && pod.Kind == "Pod"
}
// call before: if !isValidPodManifest(data) { return nil, fmt.Errorf("invalid kops-channels manifest") }

Try / catch

pod := &corev1.Pod{}
if err := yaml.Unmarshal(data, pod); err != nil {
	return nil, fmt.Errorf("parsing kops-channels manifest: %w", err) // inspect wrapped err with errors.As/%v
}

Prevention

When it happens

Trigger: Calling rewriteChannelsManifestForEnroll (via GetBootstrapData during toolbox enroll) with manifest bytes that are not valid YAML, are JSON/YAML of a non-Pod object, or contain fields incompatible with corev1.Pod after strict/lossless conversion by sigs.k8s.io/yaml.

Common situations: kOps cloudup changes the shape or serialization of the embedded kops-channels manifest so it no longer parses as a Pod; a user or tooling pre-modified/truncated the manifest file; bundle packaging injected placeholder text or an empty file where the Pod manifest should be.

Related errors


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