kubernetes/kops · warning

error parsing version spec %q

Error message

error parsing version spec %q

What it means

ParseChannelVersion unmarshals the value of an addons.k8s.io/<name> namespace annotation into a ChannelVersion struct and wraps JSON failures. It means the annotation recording installed addon state is not the expected JSON ({channel, id, manifestHash, systemGeneration}) — the state is corrupt or was written by an incompatible tool. Note FindChannelVersions only logs a warning for the same condition, while GetInstalledVersion propagates the error.

Source

Thrown at channels/pkg/channels/channel_version.go:82

}

func (c *ChannelVersion) String() string {
	s := "Channel=" + stringValue(c.Channel)
	if c.Id != "" {
		s += " Id=" + c.Id
	}
	if c.ManifestHash != "" {
		s += " ManifestHash=" + c.ManifestHash
	}
	s += " SystemGeneration=" + strconv.Itoa(c.SystemGeneration)
	return s
}

func ParseChannelVersion(s string) (*ChannelVersion, error) {
	v := &ChannelVersion{}
	err := json.Unmarshal([]byte(s), v)
	if err != nil {
		return nil, fmt.Errorf("error parsing version spec %q", s)
	}
	return v, nil
}

func FindChannelVersions(ns *v1.Namespace) map[string]*ChannelVersion {
	addons := make(map[string]*ChannelVersion)
	for k, v := range ns.Annotations {
		if !strings.HasPrefix(k, AnnotationPrefix) {
			continue
		}

		channelVersion, err := ParseChannelVersion(v)
		if err != nil {
			klog.Warningf("failed to parse annotation %q=%q", k, v)
			continue
		}

		name := strings.TrimPrefix(k, AnnotationPrefix)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Inspect the annotation: kubectl get namespace <ns> -o jsonpath='{.metadata.annotations.addons\.k8s\.io/<name>}' and confirm it is valid JSON like {"id":"...","manifestHash":"..."}.
  2. Delete the stale annotation so the next apply re-installs and rewrites it: kubectl annotate namespace <ns> addons.k8s.io/<name>-.
  3. Re-run 'kops update cluster --yes' to re-apply the addon and re-record the version.
  4. Confirm the kops version matches the one that created the cluster.

Example fix

# corrupt annotation: remove it so kops re-records a valid JSON value
kubectl annotate namespace kube-system addons.k8s.io/networking.k8s.io-
# then re-apply
kops update cluster --yes
Defensive patterns

Strategy: validation

Validate before calling

// validate annotation value before ParseChannelVersion
func validChannelVersion(s string) bool {
	var cv struct {
		ID           string `json:"id"`
		ManifestHash string `json:"manifestHash"`
	}
	return json.Unmarshal([]byte(s), &cv) == nil && (cv.ID != "" || cv.ManifestHash != "")
}

Type guard

func isChannelVersionJSON(s string) bool {
	var v channels.ChannelVersion
	return json.Unmarshal([]byte(s), &v) == nil
}

Try / catch

cv, err := channels.ParseChannelVersion(raw)
if err != nil {
	klog.Warningf("corrupt addons annotation %q, removing so it is re-applied: %v", raw, err)
	// delete annotation and let the next apply rewrite it
	k8sClient.CoreV1().Namespaces().Patch(ctx, ns, types.StrategicMergePatchType,
		[]byte(fmt.Sprintf(`{"metadata":{"annotations":{%q:null}}}`, annotationName)), metav1.PatchOptions{})
}

Prevention

When it happens

Trigger: GetInstalledVersion reads namespace annotation addons.k8s.io/<name> -> ParseChannelVersion fails when the value is not valid JSON or does not match the struct: a plain version string like '1.2.3', a truncated value, a hand-edited annotation, or a value written by an older incompatible kops format.

Common situations: Manual edits to namespace annotations; migration from very old kops versions that stored plain version strings; annotation truncated by a tool with size limits; copy/paste of values between addons.

Related errors


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