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

  1. Check the input files' `security` sections are well-formed JSON arrays of requirement objects
  2. Re-run with valid inputs; if reproducible, reduce to a minimal reproduction and file a bug
  3. 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

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.