Skip to content

fix(analyzer): inline bodies of the same shape took a type name from another operation - #126

Merged
giraffesyo merged 1 commit into
canaryfrom
fix/inline-body-naming
Aug 21, 2026
Merged

fix(analyzer): inline bodies of the same shape took a type name from another operation#126
giraffesyo merged 1 commit into
canaryfrom
fix/inline-body-naming

Conversation

@giraffesyo

Copy link
Copy Markdown
Member

Closes #125.

What was wrong

Synthesized types are keyed on shape, so two operations that each write the same body inline collapse onto one type, named for whichever the analyzer converted first. Seven single-file upload endpoints all took UploadStandaloneAiChatAttachmentBody.

The same dedup hits inline response bodies, so an operation could return a type named for a different endpoint. #125 assumed output types were already distinct; that holds only because huma emits those response schemas as named components. Untitled inline ones collapse the same way.

The fix

A body an operation writes inline now scopes what it synthesizes. Inside that scope the shape key is prefixed with the body, so each operation gets its own type named for itself. The scope covers the whole subtree, so a nested inline object does not leak one operation's name into another's signature either. Applied to request bodies, response bodies, SSE event payloads, and webhook and callback payloads.

Bodies the spec names stay shared:

  • a $ref to components/requestBodies or components/responses (checked with GoLow().IsReference())
  • a title: on the inline schema, or an external-file $ref, both of which already self-name
  • component schemas and everything outside an operation body

An event stream resolves one schema twice, as the response body and as the event payload. Keying on each name hint split that into two identical types, so the key is the body rather than the hint and StreamEventsResponse stays one type.

Tests

  • internal/analyzer/schemas_operation_body_test.go: per-operation naming for request and response, component $ref bodies stay shared, titled bodies stay shared, an event payload declares one type.
  • internal/generator/e2e_operation_body_naming_test.go: generates a two-upload client, compiles it, and runs it against a test server, constructing UploadUserAvatarBody and UploadWorkflowIconBody and taking *UploadUserAvatarResponse and *UploadWorkflowIconResponse back.

Both fail on canary with undefined: UploadWorkflowIconBody.

Blast radius

Regenerating every spec in testdata/ is byte identical, since those name their bodies as components. Only specs that repeat an inline shape see names move, which is the point.

…another operation

Synthesized types were keyed only on shape, so two operations that each wrote
the same body inline landed on one type, named for whichever was converted
first. Uploading a workflow icon meant constructing an
UploadStandaloneAiChatAttachmentBody. The same collapse hit inline response
bodies, where one operation returned a type named for another endpoint.

A body an operation writes inline now scopes what it synthesizes, so each
operation gets a type named for itself, nested inline objects included. Bodies
the spec names stay shared: a $ref to components/requestBodies or
components/responses, a titled schema, an external-file $ref.

An event stream resolves one schema twice, as the response body and as the
event payload, so the scope is the body rather than each name hint and the two
stay on one declared type.

Regenerating testdata is byte identical, since those specs name their bodies as
components.

Closes #125
@giraffesyo
giraffesyo merged commit f1bae04 into canary Aug 21, 2026
6 checks passed
@giraffesyo
giraffesyo deleted the fix/inline-body-naming branch August 21, 2026 22:12
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.

Inline request bodies with the same shape share a type named after one operation

1 participant