grpc-ecosystem/grpc-gateway · error
%s: components: %w
Error message
%s: components: %w
What it means
This error is returned when the top-level `components` field of an input document cannot be json.Unmarshal-ed into the library's components struct (schemas, responses, parameters, examples, requestBodies, headers, securitySchemes, links, callbacks, pathItems). Note that an explicit JSON null is tolerated and skipped; any other value with an incompatible shape for one of those keys — e.g. an array where an object is expected, or a string — fails and is wrapped as `<name>: components: <cause>`.
Source
Thrown at openapiv3-merge/internal/merge/merge.go:227
d.Info = raw
case "servers":
d.Servers = raw
case "paths":
obj, err := decodeOrderedObject(raw)
if err != nil {
return nil, fmt.Errorf("%s: paths: %w", in.Name, err)
}
d.Paths = obj
case "webhooks":
obj, err := decodeOrderedObject(raw)
if err != nil {
return nil, fmt.Errorf("%s: webhooks: %w", in.Name, err)
}
d.Webhooks = obj
case "components":
if !isJSONNull(raw) {
if err := json.Unmarshal(raw, d.Components); err != nil {
return nil, fmt.Errorf("%s: components: %w", in.Name, err)
}
}
case "security":
if err := json.Unmarshal(raw, &d.Security); err != nil {
return nil, fmt.Errorf("%s: security: %w", in.Name, err)
}
case "tags":
if err := json.Unmarshal(raw, &d.Tags); err != nil {
return nil, fmt.Errorf("%s: tags: %w", in.Name, err)
}
case "externalDocs":
d.ExternalDocs = raw
default:
d.extras.set(key, raw)
}
}
if _, err := dec.Token(); err != nil {
return nil, fmt.Errorf("%s: %w", in.Name, err)View on GitHub (pinned to a58a4436a3)
Solutions
- Fix the offending value so `components` is an object whose sub-keys are objects, e.g. "components": {"schemas": {"Pet": {...}}}.
- Check the exact cause in the wrapped error — it names the field (e.g. `json: cannot unmarshal array into Go struct field ...`) pointing at the bad sub-key.
- If components should be absent, omit the key or use null (both are handled); do not use an array or string.
- Pre-validate by unmarshalling the `components` value into a map[string]map[string]json.RawMessage before calling Merge.
Example fix
// before
{"openapi": "3.1.0", "components": {"schemas": []}}
// after
{"openapi": "3.1.0", "components": {"schemas": {"Pet": {"type": "object"}}}} Defensive patterns
Strategy: validation
Validate before calling
func validateComponentsField(data []byte) error {
var doc struct {
Components json.RawMessage `json:"components"`
}
if err := json.Unmarshal(data, &doc); err != nil {
return err
}
if len(doc.Components) == 0 || string(doc.Components) == "null" {
return nil
}
var c map[string]map[string]json.RawMessage
if err := json.Unmarshal(doc.Components, &c); err != nil {
return fmt.Errorf("components must be an object of objects: %w", err)
}
return nil
} Type guard
func isComponentsObject(raw json.RawMessage) bool {
var c map[string]map[string]json.RawMessage
return len(raw) > 0 && string(raw) != "null" && json.Unmarshal(raw, &c) == nil
} Try / catch
merged, err := merger.Merge(inputs)
if err != nil {
if strings.Contains(err.Error(), ": components: ") {
return fmt.Errorf("input spec has a malformed components field: %w", err)
}
return err
} Prevention
- Keep every components sub-key (schemas, responses, securitySchemes, ...) an object, never an array or scalar.
- Ensure generated structs use map types (not slices) for all components sub-sections.
- Omit components or set it to null when empty — both are accepted; avoid other placeholders.
- Validate specs against the OpenAPI 3.x JSON Schema before merging.
When it happens
Trigger: Calling Merge with an Input whose Data contains `"components": "none"`, `"components": []`, `"components": {"schemas": []}`, `"components": {"securitySchemes": "basic"}` — i.e. components itself or any of its known sub-keys has the wrong JSON type.
Common situations: Generated specs where a components sub-section was an uninitialized slice (marshals to []); hand-written specs putting a scalar where an object belongs; tool output that nests components differently; partial migrations from OpenAPI 2.0 `definitions` placed with the wrong shape.
Related errors
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/13b16d134d9f0291.
Report an issue: GitHub.