{"record":{"id":"45504bba15883acb","repo":"grpc-ecosystem/grpc-gateway","slug":"security-w","errorCode":null,"errorMessage":"security: %w","messagePattern":"security: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"openapiv3-merge/internal/merge/merge.go","lineNumber":405,"sourceCode":"}\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.)\nfunc mergeSecurity(out, src *document) error {\n\tif len(src.Security) == 0 {\n\t\treturn nil\n\t}\n\tif len(out.Security) == 0 {\n\t\tout.Security = src.Security\n\t\treturn nil\n\t}\n\ta, err := json.Marshal(out.Security)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"security: %w\", err)\n\t}\n\tb, err := json.Marshal(src.Security)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"security: %w\", err)\n\t}\n\tsame, err := canonicalEqual(a, b)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"security: %w\", err)\n\t}\n\tif !same {\n\t\treturn fmt.Errorf(\"security: %s declares different requirements\", src.name)\n\t}\n\treturn nil\n}\n\n// mergeExtras applies first-wins to unknown top-level keys (notably\n// extensions `x-*`). Conflicting redeclarations from later inputs are\n// silently ignored, matching the policy for info/servers/etc.","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/grpc-ecosystem/grpc-gateway/blob/a58a4436a376a4bcc7d8f10c4d4f919a8438bba9/openapiv3-merge/internal/merge/merge.go#L387-L423","documentation":"mergeSecurity wraps a json.Marshal error for the already-accumulated root `security` array. The merge compares each input's security requirements against the accumulated one by marshalling both to JSON; if marshalling the accumulated value fails (practically impossible for normal parsed documents), this error is returned. It indicates the in-memory security slice cannot be serialized.","triggerScenarios":"Merge runs where two or more inputs declare non-empty root `security` and json.Marshal on the accumulated out.Security fails (e.g. an unencodable value was placed into the security slice).","commonSituations":"Extremely rare in practice; would indicate internal state corruption or a custom embedding of the merge package injecting unencodable data into the document struct.","solutions":["Check the input files' `security` sections are well-formed JSON arrays of requirement objects","Re-run with valid inputs; if reproducible, reduce to a minimal reproduction and file a bug","Verify you are not embedding/patching the merge package's document structs directly"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"b, err := os.ReadFile(path)\nif err != nil { return err }\nvar doc struct {\n    Security json.RawMessage `json:\"security\"`\n}\nif err := json.Unmarshal(b, &doc); err != nil { return err }\nif len(doc.Security) > 0 {\n    var sec []map[string][]string\n    if err := json.Unmarshal(doc.Security, &sec); err != nil {\n        return fmt.Errorf(\"%s: security section malformed\", path)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := merge.Merge(inputs); err != nil {\n    if strings.HasPrefix(err.Error(), \"security: \") {\n        return fmt.Errorf(\"merge failed in security section: %w\", err)\n    }\n    return err\n}","preventionTips":["Do not mutate the merged document struct between merge stages","Validate security sections parse as arrays of requirement objects before merging","Treat persistent marshal failures as a bug report with a minimal repro"],"tags":["go","json","openapi","serialization"],"backgroundTag":"json-marshal-failed","analyzedSha":"a58a4436a376a4bcc7d8f10c4d4f919a8438bba9","analyzedAt":"2026-09-02T10:28:31.537Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}