Support per-operation custom error response schemas

Author: andreas-04Created Apr 27, 2026Updated Apr 28, 2026
LabelsOpenAPI v3

Feature

protoc-gen-openapiv3 currently auto-injects a single default response pointing to google.rpc.Status for every operation. This is fine for the "happy path + one error shape" case, but many production gRPC services return multiple distinct error payloads for the same HTTP status code, and there is currently no way to document them in the generated spec.

Use Case

Consider a service where a single endpoint can return 400 Bad Request for two semantically different reasons, each with a different JSON payload structure:

proto
 service Service {
  rpc Delete(DeleteRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = { delete: "/v1/foo/{foo_id}" };
    // Can return 400 because:
    //   - ErrCannotDelete  (grpc: FAILED_PRECONDITION) - foo is running
    //   - ErrNotFound      (grpc: INVALID_ARGUMENT)    - foo doesn't exist
  }
}

The correct OpenAPI representation uses oneOf:

yaml
"400": {
  "description": "ErrCannotDelete | ErrNotFound",
  "content": {
    "application/json": {
      "schema": {
        "oneOf": [
          { "type": "object", "properties": { "error": { "type": "string" } }, "x-error-name": "ErrCannotDelete" },
          { "type": "object", "properties": { "error": { "type": "string" } }, "x-error-name": "ErrNotFound" }
        ]
      }
    }
  }
}

There is no existing annotation that carries this information into the generator.

The generator should:

  • Group declared errors by http_code.
  • Emit a single oneOf response schema for codes with more than one error, and a plain schema for codes with exactly one error.
  • Keep the auto-injected default: google.rpc.Status for undeclared errors (or suppress it with disable_default_errors).

Source: grpc-ecosystem/grpc-gateway