kubernetes/kops · error
invalid key/value pair %q (expected separator %q)
Error message
invalid key/value pair %q (expected separator %q)
What it means
parseKeyValueList splits a comma-separated list and each entry on the given separator ('<' or '='). If an entry does not contain the expected separator, it returns "invalid key/value pair %q (expected separator %q)", which callers wrap with the field name (evictionHard/evictionSoft/evictionSoftGracePeriod/evictionMinimumReclaim).
Source
Thrown at nodeup/pkg/model/kubelet.go:527
// parseKeyValueList parses a comma-separated list of key/value pairs
// separated by sep (for example "memory.available<100Mi" with sep="<").
// Whitespace around keys and values is trimmed. An empty input returns
// (nil, nil) so callers can leave the corresponding kubelet config field
// unset. Returns an error if any entry is missing the separator.
//
// The kops API uses these CSV strings for fields that kubelet represents
// as map[string]string: eviction-hard / eviction-soft use "<", while
// eviction-soft-grace-period and eviction-minimum-reclaim use "=".
func parseKeyValueList(in string, sep string) (map[string]string, error) {
if in == "" {
return nil, nil
}
result := make(map[string]string, strings.Count(in, ",")+1)
for kv := range strings.SplitSeq(in, ",") {
k, v, ok := strings.Cut(kv, sep)
if !ok {
return nil, fmt.Errorf("invalid key/value pair %q (expected separator %q)", kv, sep)
}
result[strings.TrimSpace(k)] = strings.TrimSpace(v)
}
return result, nil
}
// parseTaint converts the kops "key=value:Effect" taint string (the form
// historically passed to --register-with-taints) into a v1.Taint, the type
// the kubelet config field RegisterWithTaints requires.
func parseTaint(s string) (v1.Taint, error) {
parsed, err := kopsutil.ParseTaint(s)
if err != nil {
return v1.Taint{}, err
}
return v1.Taint{
Key: parsed["key"],
Value: parsed["value"],
Effect: v1.TaintEffect(parsed["effect"]),View on GitHub (pinned to 4c8573c808)
Solutions
- Fix the quoted entry to include the expected separator (see %q in the message)
- Match separator to field: '<' for evictionHard/Soft, '=' for grace period/minimum reclaim
- Remove stray commas / empty segments from the list
- Validate the string with a local split before applying to the cluster
Example fix
// before
parseKeyValueList("memory.available<100Mi,nodefs.available", "<")
// after
parseKeyValueList("memory.available<100Mi,nodefs.available<10%", "<") Defensive patterns
Strategy: validation
Validate before calling
func validateKVList(in, sep string) error {
if in == "" { return nil }
for _, kv := range strings.Split(in, ",") {
if !strings.Contains(kv, sep) {
return fmt.Errorf("entry %q missing separator %q", kv, sep)
}
}
return nil
} Try / catch
if _, err := parseKeyValueList(userInput, "<"); err != nil {
var invalid *invalidKVError
if errors.As(err, &invalid) {
return fmt.Errorf("re-enter the list as comma-separated key<value pairs: %w", err)
}
return err
} Prevention
- Verify each comma-separated entry contains the expected separator before submitting
- Use '<' for eviction thresholds, '=' for grace periods and minimum reclaims
- Strip whitespace and trailing commas from hand-edited lists
- Add a spec-validation step in CI before kops update cluster
When it happens
Trigger: parseKeyValueList -> strings.Cut(kv, sep) returns ok=false for some entry: e.g. parseKeyValueList("memory.available100Mi", "<") or an empty segment from a trailing comma.
Common situations: Hand-editing kubelet eviction settings in the cluster spec; separator confusion between the '<' fields (evictionHard/evictionSoft) and '=' fields (grace period, minimum reclaim); trailing/leading commas creating separator-less empty entries.
Related errors
- evictionHard: %w
- evictionSoft: %w
- evictionSoftGracePeriod: %w
- evictionMinimumReclaim: %w
- featureGates: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/7fc3a5e6937b1664.
Report an issue: GitHub.