grpc-ecosystem/grpc-gateway · error
expected string key, got %v
Error message
expected string key, got %v
What it means
While streaming tokens of a JSON object, decodeOrderedObject expects every key token to be a string (as JSON requires). A non-string token appearing where a key should be means the byte stream is not a well-formed JSON object (e.g. the value of the previous pair ran into the next key, or the buffer is corrupted). Under valid JSON this is nearly unreachable, but it guards the token stream.
Source
Thrown at openapiv3-merge/internal/merge/merge.go:570
}
dec := json.NewDecoder(bytes.NewReader(raw))
dec.UseNumber()
tok, err := dec.Token()
if err != nil {
return nil, err
}
if d, ok := tok.(json.Delim); !ok || d != '{' {
return nil, fmt.Errorf("expected JSON object, got %v", tok)
}
out := newOrderedObject()
for dec.More() {
tok, err := dec.Token()
if err != nil {
return nil, err
}
k, ok := tok.(string)
if !ok {
return nil, fmt.Errorf("expected string key, got %v", tok)
}
var v json.RawMessage
if err := dec.Decode(&v); err != nil {
return nil, err
}
out.set(k, v)
}
if _, err := dec.Token(); err != nil {
return nil, err
}
return out, nil
}
View on GitHub (pinned to a58a4436a3)
Solutions
- Re-read the input file bytes (check encoding and for corruption) and validate with `jq .` before merging
- Ensure you pass complete file contents, not sliced or partially decoded RawMessage, into the merge API
- Re-export/regenerate the offending spec file
Example fix
// before: partially decoded fragment passed to parse
raw := data[10:]
// after: pass the full document
raw := data
merge.Merge([]merge.Input{{Name: "spec.json", Data: raw}}) Defensive patterns
Strategy: validation
Validate before calling
// Confirm inputs are well-formed JSON objects before invoking the merge pipeline
for _, f := range files {
b, err := os.ReadFile(f)
if err != nil { return err }
if !json.Valid(b) {
return fmt.Errorf("%s: not valid JSON", f)
}
} Try / catch
if err := merge.Merge(inputs); err != nil {
if strings.Contains(err.Error(), "expected string key") {
return fmt.Errorf("input JSON stream is corrupted; re-export the spec: %w", err)
}
return err
} Prevention
- Pass complete, unmodified file bytes to the merge API — never sliced RawMessage
- Check files for binary corruption or encoding problems after transfers
- Run json.Valid on all inputs before merging
When it happens
Trigger: decodeOrderedObject iterating keys via dec.More()/Token() encounters a token that is not a string — only possible with malformed JSON input that slipped past the initial '{' check, such as structurally corrupted raw bytes or a hand-crafted RawMessage passed to parse.
Common situations: Programmatic use of the internal parse function with corrupted or hand-built RawMessage input; binary corruption or wrong-encoding reads of the spec file in unusual setups.
Related errors
- invalid tag entry: %w
- expected JSON object, got %v
- %s: %w
- %s: expected JSON object at top level
- %s: unexpected token %v
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/78ca5804f45f61c9.
Report an issue: GitHub.