Skip to content

fix: emit case clauses for bodyless responses to prevent default catch-all unmarshal error#2427

Open
lwc wants to merge 1 commit into
oapi-codegen:mainfrom
lwc:fix/bodyless-response-default-catch-all
Open

fix: emit case clauses for bodyless responses to prevent default catch-all unmarshal error#2427
lwc wants to merge 1 commit into
oapi-codegen:mainfrom
lwc:fix/bodyless-response-default-catch-all

Conversation

@lwc

@lwc lwc commented Jun 23, 2026

Copy link
Copy Markdown

When a spec defines a response without content (e.g. 204 No Content) alongside a default error response with JSON content, the generated Parse*Response function would attempt to json.Unmarshal an empty body because the default catch-all case (&& true) matched any status code.

Bodyless responses produce no type definitions, so the existing loop never visited them and no guarding case clause was emitted.

This adds a second pass over all declared responses that emits explicit break clauses for any response without content, placed before the default catch-all in the generated switch statement.

Fixes #2426

@lwc lwc requested a review from a team as a code owner June 23, 2026 04:14
@greptile-apps

greptile-apps Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR updates client response parsing for bodyless OpenAPI responses. The main changes are:

  • Adds no-content switch cases for declared responses without content.
  • Keeps exact bodyless status codes ahead of catch-all response parsing.
  • Adjusts bodyless wildcard response ordering to avoid shadowing explicit content responses.
  • Adds a regression fixture and test for bodyless responses with JSON defaults.

Confidence Score: 3/5

This is close, but the wildcard bodyless response ordering should be fixed before merging.

  • Exact bodyless status handling appears covered.

  • Bodyless wildcard responses can still fall through to JSON default parsing before the no-content break.

  • A bodyless success response with a JSON content type header can still return an EOF parse error.

  • pkg/codegen/template_helpers.go

Important Files Changed

Filename Overview
pkg/codegen/template_helpers.go Adds no-content response cases, but bodyless wildcard responses can still sort after JSON default catch-all parsing.
pkg/codegen/codegen_test.go Adds regression coverage for exact bodyless responses and explicit status ordering.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
pkg/codegen/template_helpers.go:268-269
**Range guard still late**

The no-content range key sorts as `9.nocontent.2XX`, while generated JSON default catch-all keys sort earlier, such as `9.json.default`. For an operation with `2XX` bodyless plus a JSON `default`, a `204` response that includes `Content-Type: application/json` still enters the default JSON unmarshal case before the `2XX` break and returns an EOF error on the empty body. The range guard needs to come after explicit same-range content cases but before the default catch-all.

Reviews (2): Last reviewed commit: "fix: emit case clauses for bodyless resp..." | Re-trigger Greptile

Comment thread pkg/codegen/template_helpers.go Outdated
@lwc lwc force-pushed the fix/bodyless-response-default-catch-all branch 2 times, most recently from 245e50e to 158e810 Compare June 23, 2026 04:27
Comment thread pkg/codegen/template_helpers.go Outdated
Comment on lines +268 to +269
caseKey := fmt.Sprintf("%s.nocontent.%s", prefix, responseName)
handledCaseClauses[caseKey] = caseClause

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Range guard still late

The no-content range key sorts as 9.nocontent.2XX, while generated JSON default catch-all keys sort earlier, such as 9.json.default. For an operation with 2XX bodyless plus a JSON default, a 204 response that includes Content-Type: application/json still enters the default JSON unmarshal case before the 2XX break and returns an EOF error on the empty body. The range guard needs to come after explicit same-range content cases but before the default catch-all.

Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/codegen/template_helpers.go
Line: 268-269

Comment:
**Range guard still late**

The no-content range key sorts as `9.nocontent.2XX`, while generated JSON default catch-all keys sort earlier, such as `9.json.default`. For an operation with `2XX` bodyless plus a JSON `default`, a `204` response that includes `Content-Type: application/json` still enters the default JSON unmarshal case before the `2XX` break and returns an EOF error on the empty body. The range guard needs to come after explicit same-range content cases but before the default catch-all.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK should be fixed now.

@lwc lwc force-pushed the fix/bodyless-response-default-catch-all branch 2 times, most recently from 538bb04 to 158e810 Compare June 23, 2026 04:48
…h-all unmarshal error

When a spec defines a response without content (e.g. 204 No Content)
alongside a default error response with JSON content, the generated
Parse*Response function would attempt to json.Unmarshal an empty body
because the default catch-all case (&& true) matched any status code.

Bodyless responses produce no type definitions, so the existing loop
never visited them and no guarding case clause was emitted.

This adds a second pass over all declared responses that emits explicit
break clauses for any response without content. Sort key selection
ensures correct precedence:

- Exact status codes (e.g. 204) sort before content-handling cases,
  safe because they can only match their own status code.
- Range wildcards (e.g. 2XX) sort alongside content-handling cases,
  preventing a bodyless range from shadowing an explicit response
  (e.g. 200) that does have content.
- default is skipped (a bodyless default is degenerate).
@lwc lwc force-pushed the fix/bodyless-response-default-catch-all branch from 158e810 to e65caa4 Compare June 23, 2026 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant