kubernetes/kops · error
unhandled state for json value (%T %q) serialization: %v %q
Error message
unhandled state for json value (%T %q) serialization: %v %q
What it means
After a value token passes the type switch, the writer serializes it according to the current state character. Valid states are '{' (a field name follows in an object), '[' (an array element), and 'F' (the value of a field). Any other state (including state 0, i.e. a bare value at the top level) has no serialization rule, so a JSON value was written where the state machine does not expect one.
Source
Thrown at pkg/jsonutils/streamwriter.go:172
j.path = append(j.path, fmt.Sprintf("%s", token))
return j.writeRaw(j.indent + v + ": ")
case '[':
if err := j.writeRaw(j.indent + v); err != nil {
return err
}
j.deferred = ",\n"
return nil
case 'F':
j.state = j.state[:len(j.state)-1]
j.path = j.path[:len(j.path)-1]
if err := j.writeRaw(v); err != nil {
return err
}
j.deferred = ",\n"
return nil
}
return fmt.Errorf("unhandled state for json value (%T %q) serialization: %v %q", token, v, state, j.state)
}
func (j *JSONStreamWriter) writeRaw(s string) error {
if j.deferred != "" {
if _, err := j.out.Write([]byte(j.deferred)); err != nil {
return err
}
j.deferred = ""
}
_, err := j.out.Write([]byte(s))
return err
}
View on GitHub (pinned to 4c8573c808)
Solutions
- Start the token stream with json.Delim('{') or json.Delim('['); wrap bare scalars in an object/array.
- Emit alternating field-name then value tokens inside objects.
- Use a fresh writer per document and feed tokens in decoder order.
Example fix
// before
w.WriteToken("hello") // top-level scalar, state==0
// after
w.WriteToken(json.Delim('{'))
w.WriteToken("msg")
w.WriteToken("hello")
w.WriteToken(json.Delim('}')) Defensive patterns
Strategy: validation
Validate before calling
// Only call WriteToken with value tokens while inside an object (after a field name)
// or an array. Reject top-level scalar documents:
first, _ := dec.Token()
if d, ok := first.(json.Delim); !ok || (d != '{' && d != '[') {
return fmt.Errorf("document must start with an object or array")
} Type guard
func docStartsWithContainer(first json.Token) bool {
d, ok := first.(json.Delim)
return ok && (d == '{' || d == '[')
} Try / catch
if err := writer.WriteToken(tok); err != nil {
return fmt.Errorf("cannot serialize token %v in current state: %w", tok, err)
} Prevention
- Always open a document with '{' or '[' before writing values.
- Alternate field-name/value tokens strictly inside objects.
- Keep field name strings and value strings distinguishable in your token pipeline.
When it happens
Trigger: Writing a scalar token at top level before any '{' or '[' delimiter (state is 0); writing two field-name strings in a row without a value between them; continuing a writer whose prior stream was aborted.
Common situations: Streaming a bare JSON string/number (valid JSON per RFC 7159) — the writer only supports documents rooted in objects/arrays; misordered hand-driven token sequences.
Related errors
- unhandled state for json delim serialization: %v %q
- unknown delim: %v
- unhandled token type %T
- error parsing version spec %q
- error encoding version spec: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/937413263e190cd1.
Report an issue: GitHub.