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

  1. Fix the offending value so `components` is an object whose sub-keys are objects, e.g. "components": {"schemas": {"Pet": {...}}}.
  2. 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.
  3. If components should be absent, omit the key or use null (both are handled); do not use an array or string.
  4. 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

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.