grpc-ecosystem/grpc-gateway · error

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

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.

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)

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.