grpc-ecosystem/grpc-gateway · error

components. . : redefines an entry with a different value

Error message

components.%s.%q: %s redefines an entry with a different value

What it means

Raised in mergeComponents when two inputs define the same-named component (e.g. components.schemas."example.v1.User") with canonically different values. The strict merger rejects conflicting redefinitions, naming the component kind, key, and the input file that redefined it.

Solutions

  1. Rename one of the conflicting components (e.g. fully-qualify proto names so they stay unique)
  2. Make both definitions identical if the duplication is unintentional
  3. Move the shared component into a single input that the others reference via $ref
  4. Align the source definitions (proto messages) so generated schemas match

Example fix

// before (b.json)
"schemas": { "example.v1.User": { ... different fields ... } }
// after (b.json)
"schemas": { "example.v2.User": { ... } }
Defensive patterns

Strategy: validation

Validate before calling

func findDuplicateComponents(inputs []merge.Input) map[string][]string {
	seen := map[string][]string{}
	for _, in := range inputs {
		var doc struct { Components map[string]map[string]json.RawMessage `json:"components"` }
		if json.Unmarshal(in.Data, &doc) != nil { continue }
		for kind, m := range doc.Components {
			for k := range m { seen[kind+"."+k] = append(seen[kind+"."+k], in.Name) }
		}
	}
	dups := map[string][]string{}
	for k, v := range seen { if len(v) > 1 { dups[k] = v } }
	return dups
}

Try / catch

merged, err := merge.Merge(inputs)
if err != nil {
	if strings.Contains(err.Error(), "components.") && strings.Contains(err.Error(), "redefines") {
		// resolve the component name collision before retrying
	}
	return err
}

Prevention

When it happens

Trigger: Calling Merge where two documents declare the same schema/response/parameter/etc. name with different definitions — e.g. two proto files defining the same message name with different fields, so generated schemas differ.

Common situations: Name collisions across proto packages after stripping qualifiers, one team updating a shared schema in their copy only, vendored specs redefining common types, or version-skewed generator outputs for the same type.

Related errors


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

Appendix: source

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

		{"links", &dst.Links, &src.Links},
		{"callbacks", &dst.Callbacks, &src.Callbacks},
		{"pathItems", &dst.PathItems, &src.PathItems},
	}
	for _, p := range pairs {
		if len(*p.src) == 0 {
			continue
		}
		if *p.dst == nil {
			*p.dst = make(map[string]json.RawMessage, len(*p.src))
		}
		for k, v := range *p.src {
			if prev, dup := (*p.dst)[k]; dup {
				same, err := canonicalEqual(prev, v)
				if err != nil {
					return fmt.Errorf("components.%s.%s: %w", p.name, k, err)
				}
				if !same {
					return fmt.Errorf("components.%s.%q: %s redefines an entry with a different value", p.name, k, srcName)
				}
				continue
			}
			(*p.dst)[k] = v
		}
	}
	return nil
}

// mergeTags appends tags from src to out, deduplicating by `name`. Two tag
// entries sharing a name must declare identical metadata.
func mergeTags(out *document, seen map[string]json.RawMessage, src *document) error {
	for _, raw := range src.Tags {
		name, err := tagName(raw)
		if err != nil {
			return fmt.Errorf("%s: tags: %w", src.name, err)
		}
		if prev, ok := seen[name]; ok {

View on GitHub (pinned to a58a4436a3)