Skip to content

fix(protoc-gen-openapiv2): fix naming cache for multi-file generation#6315

Merged
johanbrandhorst merged 1 commit intogrpc-ecosystem:mainfrom
franchb:fix-openapi-panic
Feb 6, 2026
Merged

fix(protoc-gen-openapiv2): fix naming cache for multi-file generation#6315
johanbrandhorst merged 1 commit intogrpc-ecosystem:mainfrom
franchb:fix-openapi-panic

Conversation

@franchb
Copy link
Copy Markdown
Contributor

@franchb franchb commented Feb 3, 2026

Summary

Properly fixes #6274 (panic when processing multiple proto files) without causing #6308 (naming inconsistency regression).

This replaces the approach from PR #6275 which was reverted.

Root Cause

The fundamental issue was execution order in applyTemplate():

  • renderServices() was called first, using/building the cache for $ref generation
  • Cache was then rebuilt with filtered names
  • renderMessagesAsDefinition() used the NEW filtered cache for definitions
  • Result: $ref and definition names could mismatch

Solution

Move cache initialization BEFORE renderServices():

  1. Pre-scan services to collect referenced names WITHOUT using the cache
  2. Build filtered names and initialize cache upfront
  3. All subsequent lookups use the same consistent cache

Changes

  • Add collectReferencedNamesForCache() - scans services/messages without using cache
  • Add collectNestedTypeFQNs() - recursively collects nested type FQNs
  • Restructure applyTemplate() to initialize cache before renderServices()

Test Plan

🤖 Generated with Claude Code

Properly fixes grpc-ecosystem#6274 (panic) without causing grpc-ecosystem#6308 (naming mismatch).
Replaces the reverted approach from PR grpc-ecosystem#6275.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor Author

@franchb franchb left a comment

Choose a reason for hiding this comment

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

Code Review

Overview

This PR fixes a race condition/ordering bug in the OpenAPI v2 generator when processing multiple proto files. The fix restructures applyTemplate() to initialize the naming cache before renderServices() is called, ensuring all subsequent lookups use consistent naming.

Strengths

Root cause fix - Addresses execution order rather than patching symptoms
Clear architecture - Pre-scanning to build cache before usage is sound
Excellent test coverage - Both regression scenarios are tested
Well-documented - Good explanatory comments throughout
Follows conventions - Matches existing code patterns and style

Code Quality Observations

1. Edge case verification (template.go:572-594)
The cycle detection in collectNestedTypeFQNs looks correct - it only recurses into messages since enums don't have children. Good pattern.

2. Error handling consistency (template.go:563-566)

if statusMsg, err := reg.LookupMsg("google.rpc", "Status"); err == nil {
    collectNestedTypeFQNs(statusMsg, reg, refs)
}

The error is silently ignored, which matches the existing pattern at lines 2225-2230. Consider adding a debug log for troubleshooting, but not blocking.

3. Test helper duplication (generator_test.go:2191-2227)
The new requireGenerateWithNamingStrategy helper is nearly identical to requireGenerate. Minor suggestion: could refactor to use optional parameters or a config struct to reduce duplication.

Performance

  • Adds one additional O(n) scan pass over services/messages
  • For typical protobuf definitions, overhead is negligible
  • Actually improves performance by avoiding mid-execution cache rebuilds

Test Coverage

Excellent coverage with realistic scenarios:

  • TestGenerateMergeFilesWithBodyAndPathParams - validates #6274 panic fix
  • TestGenerateMultiFileNamingConsistency - validates #6308 $ref consistency
  • Tests verify correctness, not just "no panic"

Recommendation

✅ Approve - Well-crafted fix that properly addresses the root cause. Ready to merge once CI passes.


🤖 Reviewed with Claude Code

@johanbrandhorst
Copy link
Copy Markdown
Collaborator

Thanks for your PR, @codeout-ssol, any chance you could try and build the plugin from this PR to confirm that this is not causing your panic? Thanks!

@dbuduev dbuduev mentioned this pull request Feb 3, 2026
1 task
@franchb
Copy link
Copy Markdown
Contributor Author

franchb commented Feb 6, 2026

Note: I have successfully executed the script from the GitHub issue link here and observed no errors during the process.

@johanbrandhorst
Copy link
Copy Markdown
Collaborator

Thanks @franchb, sounds good enough to me!

@johanbrandhorst johanbrandhorst merged commit bc70149 into grpc-ecosystem:main Feb 6, 2026
14 checks passed
franchb added a commit to franchb/grpc-gateway that referenced this pull request Feb 16, 2026
…sages (grpc-ecosystem#6366)

Fix two bugs in collectReferencedNamesForCache() introduced by PR grpc-ecosystem#6315
that caused a panic ("can't resolve OpenAPI ref from typename") when a
service method returned a message containing another message with an
enum field, particularly with multi-component package names like
"example.v1".

Bug 1: Message FQMNs were pre-populated in the refs map before scanning
services, causing collectNestedTypeFQNs to short-circuit on
already-visited entries and miss nested enum types.

Bug 2: The package filter compared only the first dot-component (e.g.
"example") against the full package name (e.g. "example.v1"), which
always failed for multi-component packages.

Fixes grpc-ecosystem#6366

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
franchb added a commit to franchb/grpc-gateway that referenced this pull request Feb 16, 2026
…sages (grpc-ecosystem#6366)

Fix two bugs in collectReferencedNamesForCache() introduced by PR grpc-ecosystem#6315
that caused a panic ("can't resolve OpenAPI ref from typename") when a
service method returned a message containing another message with an
enum field, particularly with multi-component package names like
"example.v1".

Bug 1: Message FQMNs were pre-populated in the refs map before scanning
services, causing collectNestedTypeFQNs to short-circuit on
already-visited entries and miss nested enum types.

Bug 2: The package filter compared only the first dot-component (e.g.
"example") against the full package name (e.g. "example.v1"), which
always failed for multi-component packages.

Fixes grpc-ecosystem#6366

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
johanbrandhorst pushed a commit that referenced this pull request Feb 17, 2026
…sages (#6366) (#6367)

Fix two bugs in collectReferencedNamesForCache() introduced by PR #6315
that caused a panic ("can't resolve OpenAPI ref from typename") when a
service method returned a message containing another message with an
enum field, particularly with multi-component package names like
"example.v1".

Bug 1: Message FQMNs were pre-populated in the refs map before scanning
services, causing collectNestedTypeFQNs to short-circuit on
already-visited entries and miss nested enum types.

Bug 2: The package filter compared only the first dot-component (e.g.
"example") against the full package name (e.g. "example.v1"), which
always failed for multi-component packages.

Fixes #6366

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

protoc-gen-openapiv2 panics when generating OpenAPI for services with messages in separate files (Protobuf Edition 2023)

2 participants