grpc-ecosystem/grpc-gateway · error

tags[%q]: %s redefines a tag with different metadata

Error message

tags[%q]: %s redefines a tag with different metadata

What it means

openapiv3-merge rejects specs where two inputs define a top-level tag with the same `name` but different metadata. Tags are deduplicated by name; duplicate names with differing metadata are an OpenAPI spec violation, so the merge fails rather than silently keeping one version. The message names the tag and which input file caused the conflict.

Source

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

	}
	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 {
			same, err := canonicalEqual(prev, raw)
			if err != nil {
				return fmt.Errorf("tags[%q]: %w", name, err)
			}
			if !same {
				return fmt.Errorf("tags[%q]: %s redefines a tag with different metadata", name, src.name)
			}
			continue
		}
		seen[name] = raw
		out.Tags = append(out.Tags, raw)
	}
	return nil
}

// mergeSecurity applies first-wins to the root `security` array. The first
// input to declare a non-empty `security` value establishes it; later
// inputs that declare a different non-empty value are an error. (The root
// `security` is a list of alternatives that apply across the whole API; if
// two generators disagree, silently keeping one would change what callers
// are allowed to do.)
func mergeSecurity(out, src *document) error {
	if len(src.Security) == 0 {
		return nil

View on GitHub (pinned to a58a4436a3)

Solutions

  1. Make the duplicate tag metadata identical across all input files (copy one tag definition to the other spec)
  2. Remove the duplicate tag entry from one of the inputs and let the first-wins merge supply it
  3. Centralize shared tags in a single spec or generate all specs from one source of truth
  4. Check that all specs were generated with the same tool version so tag metadata matches

Example fix

// before: a.json {"tags":[{"name":"pets","description":"Pet API"}]}
//         b.json {"tags":[{"name":"pets","description":"All pets"}]}
// after: make b.json match
//        b.json {"tags":[{"name":"pets","description":"Pet API"}]}
Defensive patterns

Strategy: validation

Validate before calling

func checkTagConsistency(files []string) error {
    seen := map[string]string{}
    for _, f := range files {
        var doc struct {
            Tags []struct {
                Name        string `json:"name"`
                Description string `json:"description"`
            } `json:"tags"`
        }
        b, _ := os.ReadFile(f)
        if err := json.Unmarshal(b, &doc); err != nil { return err }
        for _, t := range doc.Tags {
            key := t.Name + "|" + t.Description
            if prev, ok := seen[t.Name]; ok && prev != key {
                return fmt.Errorf("tag %q differs between %s and a previous file", t.Name, f)
            }
            seen[t.Name] = key
        }
    }
    return nil
}

Type guard

func sameTagMetadata(a, b json.RawMessage) bool {
    var x, y map[string]any
    _ = json.Unmarshal(a, &x)
    _ = json.Unmarshal(b, &y)
    return reflect.DeepEqual(x, y)
}

Try / catch

if err := merge.Merge(inputs); err != nil {
    var conflictErr *ConflictError
    if strings.Contains(err.Error(), "redefines a tag with different metadata") {
        // surface which tag and files conflict; ask user to align metadata
    }
    return err
}

Prevention

When it happens

Trigger: Running `openapiv3-merge a.json b.json` where both a and b contain a root `tags` entry with the same `name` but different values for any other field (description, externalDocs, extensions), and canonicalEqual reports them as not identical.

Common situations: Two teams independently document the same shared tag in their specs (e.g. different `description` for `pets`); one spec was regenerated with an updated tag description while the other was not; tools adding differing vendor extensions (x-*) to the same tag.

Related errors


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