Skip to content

Fix nested body path initialization for oneof fields - #6948

Merged
johanbrandhorst merged 5 commits into
grpc-ecosystem:mainfrom
cyphercodes:fix-6938-nested-oneof-body
Jul 9, 2026
Merged

johanbrandhorst merged 5 commits into
grpc-ecosystem:mainfrom
cyphercodes:fix-6938-nested-oneof-body

Conversation

@cyphercodes

Copy link
Copy Markdown
Contributor

References to other Issues or PRs

Fixes #6938

Have you read the Contributing Guidelines?

Yes.

Brief description of what is fixed or changed

AssignableExprPrep now initializes singular intermediate message fields before descending into nested body/path field expressions. This prevents generated gateway handlers from dereferencing a nil parent message when a body selector traverses through a message field to a oneof field.

A regression test covers the input.input_value shape from the issue and verifies the parent message initialization is emitted before the oneof wrapper initialization.

Other comments

Tests run:

  • go test ./internal/descriptor ./protoc-gen-grpc-gateway/...

@johanbrandhorst johanbrandhorst left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for this PR! Could you make a change to one of our example protobuf files that would reproduce this bug, so we can protect against it breaking again in the future? See examples/internal/proto.

@cyphercodes

Copy link
Copy Markdown
Contributor Author

Updated to address the review request by adding a protobuf fixture that reproduces the nested body path through an intermediate message to a oneof field. I also excluded internal/descriptor/testdata from the default generation template so the fixture can live in-tree without being emitted by the OpenAPI generator, which currently requires top-level body fields.

Verification:

  • buf lint internal/descriptor/testdata/v1/nested_body_oneof.proto
  • make proto
  • go test ./internal/descriptor
  • buf generate --path internal/descriptor/testdata/v1/nested_body_oneof.proto --template /tmp/grpc_gateway_only.buf.gen.yaml plus assertion that generated gateway code contains protoReq.Input == nil, protoReq.Input = &ExecutionInput{}, and protoReq.Input.Input == nil
  • git diff --check

@johanbrandhorst johanbrandhorst left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This... is not what I asked for? I asked for you to ideally update one of the existing protobuf example files, but you've added a new protobuf file as testdata, and then promptly excluded it from the generation path? Please remove the changes to buf.gen.yaml and the new protobuf file, it would be much better if you just edited a_bit_of_everthing.proto or one of the others.

@dantedoyl

Copy link
Copy Markdown

@cyphercodes Hi! Any updates?

@cyphercodes

Copy link
Copy Markdown
Contributor Author

Thanks for the ping. I checked the existing-example route requested in the last review: adding a nested body path such as body: "single_nested.nested_value" in examples/internal/proto/examplepb/a_bit_of_everything.proto makes make proto fail earlier in protoc-gen-openapiv2 with:

panic: body of request "ABitOfEverythingService" is not a top level field: 'single_nested.nested_value'

The current Bazel failure is the expected generated BUILD.bazel diff for the descriptor testdata fixture that was rejected, not a separate source failure.

I don't want to broaden this PR into OpenAPI nested-body support without maintainer direction. Which direction would you prefer?

  1. allow a descriptor/gateway-only fixture outside default OpenAPI generation,
  2. point me at an existing proto path that avoids OpenAPI generation, or
  3. expand this PR to include the OpenAPI generator support too.

@johanbrandhorst

Copy link
Copy Markdown
Collaborator

I'm confused by your answer. This fixes an issue in the gateway generator, right? If so, we should definitely just go ahead and fix that same issue in the openapiv2 generator and include an example in a_bit_of_everything.proto.

@dantedoyl

Copy link
Copy Markdown

@cyphercodes Hi! Any updates?

@cyphercodes

Copy link
Copy Markdown
Contributor Author

Updated this to match the requested existing-example direction.

Changes:

  • removed the buf.gen.yaml exclusion and deleted the descriptor-only testdata proto
  • added a nested body/oneof case to examples/internal/proto/examplepb/a_bit_of_everything.proto
  • taught protoc-gen-openapiv2 to render nested body field paths instead of rejecting them as non-top-level
  • regenerated the gateway/openapi artifacts and added the example server stub

Verification:

  • go test ./internal/descriptor ./protoc-gen-openapiv2/internal/genopenapi
  • go install ./protoc-gen-grpc-gateway ./protoc-gen-openapiv2 ./protoc-gen-openapiv3
  • buf generate --path examples/internal/proto/examplepb/a_bit_of_everything.proto
  • buf generate --template ./protoc-gen-openapiv3/buf.gen.yaml --path ./examples/internal/proto/examplepb/a_bit_of_everything.proto
  • go test ./examples/internal/proto/examplepb ./examples/internal/server ./protoc-gen-grpc-gateway/internal/gengateway ./protoc-gen-openapiv2/internal/genopenapi
  • go test ./...
  • git diff --check

@dantedoyl

Copy link
Copy Markdown

@johanbrandhorst Hi! Could you review the changes?

@dantedoyl

Copy link
Copy Markdown

@johanbrandhorst ping)

Comment thread protoc-gen-openapiv2/internal/genopenapi/template.go
@cyphercodes

Copy link
Copy Markdown
Contributor Author

Updated to address the latest review and generated-artifact failure. I restored the explanatory HttpRule.body comment with an added note for nested gateway body paths, then refreshed the generated OpenAPI/clients artifacts from make generate.

Verification:

  • make generate
  • go test ./protoc-gen-openapiv2/internal/genopenapi ./examples/internal/proto/examplepb ./examples/internal/server ./protoc-gen-grpc-gateway/internal/gengateway
  • git diff --check --cached

@johanbrandhorst

Copy link
Copy Markdown
Collaborator

Looks like there's still a bazel error

@cyphercodes

Copy link
Copy Markdown
Contributor Author

Updated the Bazel BUILD files that bazel run //:gazelle reported as stale for the generated nested-body oneof client/model files.

Verification:

  • go test ./protoc-gen-openapiv2/internal/genopenapi ./examples/internal/proto/examplepb ./examples/internal/server ./protoc-gen-grpc-gateway/internal/gengateway
  • /root/go/bin/bazelisk run //:gazelle && git add -N . && git diff --exit-code -- . ':(exclude)bazel-grpc-gateway-6948'
  • git diff --check HEAD~1..HEAD

@johanbrandhorst johanbrandhorst left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@johanbrandhorst
johanbrandhorst enabled auto-merge (squash) July 9, 2026 18:13
@johanbrandhorst
johanbrandhorst merged commit 0a315fc into grpc-ecosystem:main Jul 9, 2026
15 checks passed
@claude claude Bot mentioned this pull request Aug 18, 2026
1 task
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.

Nil pointer dereference for body path through message to oneof field

3 participants