{"record":{"id":"4a1317fc7ae81bf0","repo":"grpc-ecosystem/grpc-gateway","slug":"tags-q-w","errorCode":null,"errorMessage":"tags[%q]: %w","messagePattern":"tags\\[%q\\]: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"openapiv3-merge/internal/merge/merge.go","lineNumber":376,"sourceCode":"\t\t\t}\n\t\t\t(*p.dst)[k] = v\n\t\t}\n\t}\n\treturn nil\n}\n\n// mergeTags appends tags from src to out, deduplicating by `name`. Two tag\n// entries sharing a name must declare identical metadata.\nfunc mergeTags(out *document, seen map[string]json.RawMessage, src *document) error {\n\tfor _, raw := range src.Tags {\n\t\tname, err := tagName(raw)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%s: tags: %w\", src.name, err)\n\t\t}\n\t\tif prev, ok := seen[name]; ok {\n\t\t\tsame, err := canonicalEqual(prev, raw)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"tags[%q]: %w\", name, err)\n\t\t\t}\n\t\t\tif !same {\n\t\t\t\treturn fmt.Errorf(\"tags[%q]: %s redefines a tag with different metadata\", name, src.name)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tseen[name] = raw\n\t\tout.Tags = append(out.Tags, raw)\n\t}\n\treturn nil\n}\n\n// mergeSecurity applies first-wins to the root `security` array. The first\n// input to declare a non-empty `security` value establishes it; later\n// inputs that declare a different non-empty value are an error. (The root\n// `security` is a list of alternatives that apply across the whole API; if\n// two generators disagree, silently keeping one would change what callers\n// are allowed to do.)","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/grpc-ecosystem/grpc-gateway/blob/a58a4436a376a4bcc7d8f10c4d4f919a8438bba9/openapiv3-merge/internal/merge/merge.go#L358-L394","documentation":"mergeTags wraps an error returned by canonicalEqual while comparing two tag entries that share the same `name`. canonicalEqual (merge.go:435) only errors when canonicalize() fails to re-encode one of the two raw JSON tag objects, i.e. the tag entry contains malformed or unencodable JSON. The wrap adds the conflicting tag name so you know which duplicate tag's payload could not be canonicalized.","triggerScenarios":"Merging two OpenAPI documents that both declare a top-level tag with the same name, and one of the raw tag JSON payloads cannot be canonicalized by canonicalize() during the comparison (malformed nested JSON reaching the comparison stage).","commonSituations":"Hand-edited or programmatically spliced tag objects in an input spec with subtly broken JSON structure; a spec generator emitting non-standard JSON values inside a tag object (e.g. NaN-like numbers or invalid raw fragments).","solutions":["Open both input files and locate the duplicate tag entry by the name printed in tags[\"...\"] and fix its JSON so it is a valid, canonicalizable object","Validate each input document with a JSON linter/parser before running openapiv3-merge","Regenerate the offending spec from its source generator instead of hand-editing","If the error persists, reduce the inputs to a minimal pair and file a bug with the two tag payloads"],"exampleFix":"// before (input spec A, tags section)\n{\"name\":\"pets\",\"x-meta\":{\"broken\":}}\n// after\n{\"name\":\"pets\",\"x-meta\":{\"broken\":null}}","handlingStrategy":"validation","validationCode":"for _, f := range files {\n    var doc struct {\n        Tags []json.RawMessage `json:\"tags\"`\n    }\n    b, err := os.ReadFile(f)\n    if err != nil { return err }\n    if err := json.Unmarshal(b, &doc); err != nil { return err }\n    for _, t := range doc.Tags {\n        var probe map[string]json.RawMessage\n        if err := json.Unmarshal(t, &probe); err != nil {\n            return fmt.Errorf(\"%s: tag not a valid object: %w\", f, err)\n        }\n    }\n}","typeGuard":"func isValidTagObject(raw json.RawMessage) bool {\n    var probe map[string]json.RawMessage\n    return json.Unmarshal(raw, &probe) == nil\n}","tryCatchPattern":null,"preventionTips":["Validate all input specs with a JSON parser/linter before merging","Never hand-splice JSON fragments into generated specs","Regenerate specs from source instead of editing raw JSON"],"tags":["go","json","openapi","merge-conflict"],"backgroundTag":"json-canonicalization-failed","analyzedSha":"a58a4436a376a4bcc7d8f10c4d4f919a8438bba9","analyzedAt":"2026-09-02T10:28:31.537Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}