grpc-ecosystem/grpc-gateway · error
security: %w
Error message
security: %w
What it means
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.
Source
Thrown at openapiv3-merge/internal/merge/merge.go:405
}
// 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
}
if len(out.Security) == 0 {
out.Security = src.Security
return nil
}
a, err := json.Marshal(out.Security)
if err != nil {
return fmt.Errorf("security: %w", err)
}
b, err := json.Marshal(src.Security)
if err != nil {
return fmt.Errorf("security: %w", err)
}
same, err := canonicalEqual(a, b)
if err != nil {
return fmt.Errorf("security: %w", err)
}
if !same {
return fmt.Errorf("security: %s declares different requirements", src.name)
}
return nil
}
// mergeExtras applies first-wins to unknown top-level keys (notably
// extensions `x-*`). Conflicting redeclarations from later inputs are
// silently ignored, matching the policy for info/servers/etc.View on GitHub (pinned to a58a4436a3)
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
Defensive patterns
Strategy: validation
Validate before calling
b, err := os.ReadFile(path)
if err != nil { return err }
var doc struct {
Security json.RawMessage `json:"security"`
}
if err := json.Unmarshal(b, &doc); err != nil { return err }
if len(doc.Security) > 0 {
var sec []map[string][]string
if err := json.Unmarshal(doc.Security, &sec); err != nil {
return fmt.Errorf("%s: security section malformed", path)
}
} Try / catch
if err := merge.Merge(inputs); err != nil {
if strings.HasPrefix(err.Error(), "security: ") {
return fmt.Errorf("merge failed in security section: %w", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: Extremely rare in practice; would indicate internal state corruption or a custom embedding of the merge package injecting unencodable data into the document struct.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/45504bba15883acb.
Report an issue: GitHub.