grpc-ecosystem/grpc-gateway · error
unknown message type %s
Error message
unknown message type %s
What it means
In genopenapi's nestedQueryParams, a nested (message-typed) query parameter is resolved via reg.LookupMsg; failure yields 'unknown message type %s'. The generator recursed into a query-path field that is a message, but that message isn't registered — usually because its defining file wasn't loaded during generation.
Source
Thrown at protoc-gen-openapiv2/internal/genopenapi/template.go:449
param.Default = getEnumDefault(reg, enum)
if reg.GetEnumsAsInts() {
param.Type = "integer"
param.Enum = listEnumNumbers(reg, enum)
param.Default = getEnumDefaultNumber(reg, enum)
}
}
valueComments := enumValueProtoComments(reg, enum)
if valueComments != "" {
param.Description = strings.TrimLeft(param.Description+"\n\n "+valueComments, "\n")
}
}
return []openapiParameterObject{param}, nil
}
// nested type, recurse
msg, err := reg.LookupMsg("", fieldType)
if err != nil {
return nil, fmt.Errorf("unknown message type %s", fieldType)
}
// Check for cyclical message reference:
if ok := cycle.Check(*msg.Name); !ok {
return nil, fmt.Errorf("exceeded recursive count (%d) for query parameter %q", cycle.count, fieldType)
}
// Construct a new map with the message name so a cycle further down the recursive path can be detected.
// Do not keep anything in the original touched reference and do not pass that reference along. This will
// prevent clobbering adjacent records while recursing.
touchedOut := cycle.Branch()
for _, nestedField := range msg.Fields {
if !isVisible(getFieldVisibilityOption(nestedField), reg) {
continue
}
fieldName := reg.FieldName(field)View on GitHub (pinned to a58a4436a3)
Solutions
- Pass all dependent proto files (where the nested message is defined) to the protoc invocation.
- Confirm the field's type name resolves in your proto tree (no renames/typos).
- Regenerate descriptors for the whole package set at once.
- If the message intentionally can't be exposed, flatten the query parameter structure in the request proto.
Example fix
// before protoc --openapiv2_out=. api.proto # nested request type lives in common.proto // after protoc -I . --openapiv2_out=. api.proto common.proto
Defensive patterns
Strategy: validation
Validate before calling
// Verify nested message types resolve before generating docs:
for _, t := range nestedQueryTypeNames {
if _, err := reg.LookupMsg("", t); err != nil {
return fmt.Errorf("nested message %s missing from protoc invocation", t)
}
} Prevention
- Bundle all dependency protos in the same protoc command.
- After renames, grep request messages for stale nested type references.
- Generate OpenAPI docs from a full descriptor set, not per-file fragments.
When it happens
Trigger: queryParams/nestedQueryParams recursion on a nested message field where reg.LookupMsg("", fieldType) fails — message defined in a dependency proto not passed to protoc, or the type name is stale/renamed.
Common situations: GET endpoints with deeply nested request messages whose sub-messages come from included packages not provided to protoc; generating docs for only part of the API surface; recent proto renames not fully regenerated.
Related errors
- unknown enum type %s
- failed to lookup message type %s: %w
- failed to encode OpenAPI for %s: %w
- exceeded recursive count (%d) for query parameter %q
- unsupported type: %q
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/79f79743c044f0e9.
Report an issue: GitHub.