kubernetes/kops · error

cannot decode GCE label

Error message

cannot decode GCE label: %q

What it means

DecodeGCELabel reverses EncodeGCELabel, which URI-escapes non [0-9a-z] bytes with '-' instead of '%'. Decoding turns '-' back into '%' and calls url.QueryUnescape; if that fails (e.g. a trailing or lone '%' after replacement, or an invalid hex escape like %G1), the function wraps the input string in this error. It signals that the label value was not produced by EncodeGCELabel or has been corrupted.

Solutions

  1. Ensure every label was written via EncodeGCELabel; re-encode any manually-set labels or let kops recreate them
  2. Inspect the failing label string: any '-' must decode to '%XX' with two valid hex digits; fix or remove invalid '-' sequences
  3. If labels came from an older kops version, upgrade kops and run 'kops update cluster' to re-stamp labels
  4. Wrap decode failures and skip/log the offending label instead of failing the whole etcd status scan

Example fix

// before
v, err := url.QueryUnescape(uriForm)
if err != nil {
	return "", fmt.Errorf("cannot decode GCE label: %q", s)
}
// after
// only attempt decode for kops-encoded labels; otherwise return as-is
if !strings.Contains(s, "-") {
	return s, nil
}
v, err := url.QueryUnescape(uriForm)
if err != nil {
	return "", fmt.Errorf("cannot decode GCE label: %q", s)
}
Defensive patterns

Strategy: validation

Validate before calling

func isDecodableGCELabel(s string) bool {
	uriForm := strings.ReplaceAll(s, "-", "%")
	_, err := url.QueryUnescape(uriForm)
	return err == nil
}
if !isDecodableGCELabel(label) { log.Warnf("skipping non-kops label %q", label); return }

Type guard

func isKopsEncodedLabel(s string) bool {
	// every '-' must be followed by two hex digits (from EncodeGCELabel escaping)
	for i := 0; i < len(s); i++ {
		if s[i] == '-' && (i+2 >= len(s) || !isHex(s[i+1]) || !isHex(s[i+2])) {
			return false
		}
	}
	return true
}

Try / catch

decoded, err := gce.DecodeGCELabel(label)
if err != nil {
	// treat as foreign/corrupt label: skip rather than fail the scan
	klog.V(2).Infof("ignoring undecodable label %q: %v", label, err)
	continue
}

Prevention

When it happens

Trigger: A GCE label value containing '-' that was created manually or by another tool (kops-generated labels always encode literal '-' as '--2d', so a lone '-' decodes to '%2d' and is fine only when followed by two hex digits). Passing a raw '-'-containing string like 'my-label' yields '%2d' which is valid, but 'abc%-' or a string with a single trailing '-' producing an incomplete percent-escape (e.g. 'x-1' -> 'x%1') fails QueryUnescape and triggers this error. Called from findEtcdStatus when reading etcd cluster status labels off GCE instances.

Common situations: Manually editing GCE labels in the cloud console; labels created by other controllers or older kops versions with different encoding; hand-crafting instance group names/labels with characters that produce invalid escapes; copied/mangled label strings in scripts.

Related errors


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

Appendix: source

Thrown at upup/pkg/fi/cloudup/gce/labels.go:64

		c := s[i]
		if ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') {
			b.WriteByte(c)
		} else {
			b.WriteByte('-')
			b.WriteByte("0123456789abcdef"[c>>4])
			b.WriteByte("0123456789abcdef"[c&15])
		}
	}

	return b.String()
}

// DecodeGCELabel reverse EncodeGCELabel, taking the encoded RFC1035 compatible value back to a string
func DecodeGCELabel(s string) (string, error) {
	uriForm := strings.ReplaceAll(s, "-", "%")
	v, err := url.QueryUnescape(uriForm)
	if err != nil {
		return "", fmt.Errorf("cannot decode GCE label: %q", s)
	}
	return v, nil
}

// TagForRole return the instance (network) tag used for instances with the given role.
func TagForRole(clusterName string, role kops.InstanceGroupRole) string {
	return ClusterPrefixedName(GceLabelNameRolePrefix+role.ToLowerString(), clusterName, 63)
}

View on GitHub (pinned to 4c8573c808)