grpc-ecosystem/grpc-gateway · error
%s: security: %w
Error message
%s: security: %w
What it means
This error is returned when the top-level `security` field of an input document cannot be json.Unmarshal-ed into the library's security slice type. The OpenAPI `security` field must be a JSON array of security requirement objects (e.g. [{"apiKey": []}]), so strings, objects, numbers, or null fail and are wrapped as `<name>: security: <cause>`.
Source
Thrown at openapiv3-merge/internal/merge/merge.go:232
if err != nil {
return nil, fmt.Errorf("%s: paths: %w", in.Name, err)
}
d.Paths = obj
case "webhooks":
obj, err := decodeOrderedObject(raw)
if err != nil {
return nil, fmt.Errorf("%s: webhooks: %w", in.Name, err)
}
d.Webhooks = obj
case "components":
if !isJSONNull(raw) {
if err := json.Unmarshal(raw, d.Components); err != nil {
return nil, fmt.Errorf("%s: components: %w", in.Name, err)
}
}
case "security":
if err := json.Unmarshal(raw, &d.Security); err != nil {
return nil, fmt.Errorf("%s: security: %w", in.Name, err)
}
case "tags":
if err := json.Unmarshal(raw, &d.Tags); err != nil {
return nil, fmt.Errorf("%s: tags: %w", in.Name, err)
}
case "externalDocs":
d.ExternalDocs = raw
default:
d.extras.set(key, raw)
}
}
if _, err := dec.Token(); err != nil {
return nil, fmt.Errorf("%s: %w", in.Name, err)
}
if d.OpenAPI == "" {
return nil, fmt.Errorf("%s: missing required field \"openapi\"", in.Name)
}
if isJSONNull(d.Info) {View on GitHub (pinned to a58a4436a3)
Solutions
- Edit the input so `security` is an array of requirement objects, e.g. "security": [{"apiKey": []}].
- If a single requirement applies, wrap it: {"apiKey": []} becomes [{"apiKey": []}].
- If no global security applies, omit the key entirely (or use [] for an explicitly unsecured document).
- Pre-validate by unmarshalling the `security` value into []map[string][]string before calling Merge.
Example fix
// before
{"openapi": "3.1.0", "security": {"apiKey": []}}
// after
{"openapi": "3.1.0", "security": [{"apiKey": []}]} Defensive patterns
Strategy: validation
Validate before calling
func validateSecurityField(data []byte) error {
var doc struct {
Security json.RawMessage `json:"security"`
}
if err := json.Unmarshal(data, &doc); err != nil {
return err
}
if len(doc.Security) == 0 || string(doc.Security) == "null" {
return nil
}
var s []map[string][]string
if err := json.Unmarshal(doc.Security, &s); err != nil {
return fmt.Errorf("security must be an array of requirement objects: %w", err)
}
return nil
} Type guard
func isSecurityArray(raw json.RawMessage) bool {
var s []map[string][]string
return len(raw) > 0 && json.Unmarshal(raw, &s) == nil
} Try / catch
merged, err := merger.Merge(inputs)
if err != nil {
if strings.Contains(err.Error(), ": security: ") {
return fmt.Errorf("input spec has a malformed security field: %w", err)
}
return err
} Prevention
- Always write security as an array, even for a single requirement: [{"apiKey": []}].
- When generating specs, use a slice type for Security so it marshals correctly.
- Omit the security key entirely when no global security requirements apply.
- Validate specs against the OpenAPI 3.x JSON Schema before merging.
When it happens
Trigger: Calling Merge with an Input whose Data contains `"security": "basicAuth"` (string), `"security": {"apiKey": []}` (bare object instead of array of objects), `"security": null`, or any non-array value under `security`.
Common situations: Hand-written specs where a single requirement object was written without the surrounding array; specs copied from OpenAPI 2.0 `securityDefinitions` usage; generated specs where Security was a map or string rather than a slice; templates with placeholder text under security.
Related errors
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/974ab6caff9a12b4.
Report an issue: GitHub.