Skip to content

Generated response parser fails with unmarshal error when bodyless response matches a default catch-all #2426

Description

@lwc

Description

When a spec defines a response without a content block (e.g. a 204) alongside a default response with application/json content, the generated Parse*Response function attempts to json.Unmarshal an empty body and returns an error.

The root cause is that getConditionOfResponseName returns "true" for the "default" response name, producing a catch-all case:

case strings.Contains(rsp.Header.Get("Content-Type"), "json") && true:

Since the bodyless response has no content definition, GetResponseTypeDefinitions() produces no entry for it, so no guarding case clause is emitted for that status code. When the server returns the bodyless response with a Content-Type header containing "json", the catch-all matches and json.Unmarshal fails with unexpected end of JSON input.

Minimal spec:

openapi: "3.0.0"
info:
  title: Repro
  version: "1.0"
paths:
  /events:
    post:
      operationId: createEvent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
      responses:
        "204":
          description: Event received.
        "400":
          description: Bad request.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
components:
  schemas:
    Error:
      type: object
      properties:
        code:
          type: string
        message:
          type: string

Steps to reproduce

go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen \
  -generate models,client -package api spec.yaml > api.gen.go

Then run this test:

func TestParseCreateEventResponse_204_EmptyBody(t *testing.T) {
	rsp := &http.Response{
		StatusCode: http.StatusNoContent,
		Header:     http.Header{"Content-Type": []string{"application/json"}},
		Body:       io.NopCloser(strings.NewReader("")),
	}

	resp, err := ParseCreateEventResponse(rsp)
	if err != nil {
		t.Fatalf("expected no error for 204 No Content, got: %v", err)
	}
	if resp.JSONDefault != nil {
		t.Error("expected JSONDefault to be nil for a successful 204")
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions