grpc-ecosystem/grpc-gateway · error

%s: missing required field "info"

Error message

%s: missing required field "info"

What it means

Raised in parse() when a document's top-level object has no "info" object (or it is JSON null). The OpenAPI spec requires "info", so this library rejects any input missing it. The message names the offending input document.

Source

Thrown at openapiv3-merge/internal/merge/merge.go:251

			}
		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)
	}
	if d.OpenAPI == "" {
		return nil, fmt.Errorf("%s: missing required field \"openapi\"", in.Name)
	}
	if isJSONNull(d.Info) {
		return nil, fmt.Errorf("%s: missing required field \"info\"", in.Name)
	}
	return d, nil
}

// mergeAll merges parsed documents in order. The first establishes the
// values that later inputs must not contradict.
func mergeAll(docs []*document) (*document, error) {
	first := docs[0]
	out := &document{
		name:         "merged",
		OpenAPI:      first.OpenAPI,
		Info:         first.Info,
		Servers:      first.Servers,
		Paths:        newOrderedObject(),
		Webhooks:     newOrderedObject(),
		Components:   &components{},
		ExternalDocs: first.ExternalDocs,
		extras:       newOrderedObject(),

View on GitHub (pinned to a58a4436a3)

Solutions

  1. Add a top-level "info" object with at least "title" and "version" to the named document
  2. If the value is explicitly null, replace it with a real object
  3. Fix the generator/template so it emits the info block
  4. Check that you are not accidentally passing a stripped sub-document

Example fix

// before
{ "openapi": "3.1.0", "paths": {} }
// after
{ "openapi": "3.1.0", "info": { "title": "my api", "version": "1.0.0" }, "paths": {} }
Defensive patterns

Strategy: validation

Validate before calling

func hasInfoField(data []byte) error {
	var doc map[string]json.RawMessage
	if err := json.Unmarshal(data, &doc); err != nil { return err }
	raw, ok := doc["info"]
	if !ok || string(bytes.TrimSpace(raw)) == "null" {
		return errors.New("missing required field \"info\"")
	}
	return nil
}

Type guard

func hasInfo(data []byte) bool {
	var doc struct { Info json.RawMessage `json:"info"` }
	if json.Unmarshal(data, &doc) != nil { return false }
	return len(bytes.TrimSpace(doc.Info)) > 0 && !bytes.Equal(bytes.TrimSpace(doc.Info), []byte("null"))
}

Try / catch

if err := hasInfoField(in.Data); err != nil {
	return fmt.Errorf("input %s: %w", in.Name, err)
}
merged, err := merge.Merge(inputs)

Prevention

When it happens

Trigger: Calling Merge with an Input whose Data lacks a top-level "info" object, or sets "info": null explicitly — common in generated fragments or minimal stubs.

Common situations: Generator configs that suppress metadata, hand-trimmed documents, migration tools that dropped info, or templated files where the info block was never filled in.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02). Data as JSON: /api/errors/2c2f887a093162cb. Report an issue: GitHub.