grpc-ecosystem/grpc-gateway · error
only primitive and enum types are allowed in repeated path…
Error message
only primitive and enum types are allowed in repeated path parameters
What it means
When rendering path parameters in the OpenAPI output, renderServices checks each parameter's field type. A repeated (list) path parameter whose field is a GROUP or MESSAGE type is rejected unless it is a well-known type, because a repeated message cannot be represented as a single OpenAPI path parameter. The generator returns this error instead of emitting an invalid spec.
Solutions
- Change the path template so it only references primitive/enum leaf fields, e.g. `{item_id}` for `repeated string item_id`, not a whole repeated message.
- Restructure the binding to pass the repeated message in the request body instead of the path.
- If you only need some fields, flatten them into repeated primitive fields and reference those in the path.
- If the field is a well-known type wrapper, verify descriptor.IsWellKnownType applies; otherwise convert to a primitive/enum.
Example fix
// before
option (google.api.http) = { post: "/v1/{foos=**}" body: "*" }; // repeated Foo foos
// after
option (google.api.http) = { post: "/v1/{ids=**}" body: "*" }; // repeated string ids Defensive patterns
Strategy: validation
Validate before calling
// before generation, check repeated message fields are not used in path templates
for _, m := range svc.Methods {
for _, b := range m.Bindings {
for _, p := range b.PathParams {
if p.IsRepeated() && p.Target.GetType() == descriptorpb.FieldDescriptorProto_TYPE_MESSAGE && !descriptor.IsWellKnownType(p.Target.GetTypeName()) {
return fmt.Errorf("path param %s is a repeated message; use a primitive/enum field", p.Target.GetName())
}
}
}
} Type guard
func validRepeatedPathParam(f *descriptor.Field) bool {
return !f.IsRepeated() || f.Target.GetType() != descriptorpb.FieldDescriptorProto_TYPE_MESSAGE || descriptor.IsWellKnownType(f.Target.GetTypeName())
} Try / catch
if err := applyTemplate(...); err != nil {
if strings.Contains(err.Error(), "repeated path parameters") {
return fmt.Errorf("fix google.api.http binding: %w", err)
}
return err
} Prevention
- Only reference scalar leaf fields in HTTP path templates.
- Pass repeated messages via the request body, not the URL path.
- Run protoc-gen-openapiv2 in CI to catch invalid bindings before release.
When it happens
Trigger: A proto method path binding (google.api.http) that puts a repeated message field into the URL path template, e.g. `post: "/v1/{itemsFoo=**}"` where `items` is `repeated Foo` and Foo is a message (and not a well-known type).
Common situations: Designing HTTP bindings that inline repeated sub-message fields in paths; copying a binding pattern from a repeated string path param and applying it to a message type; upgrading grpc-gateway after stricter validation was added.
Related errors
- only primitive and well-known types are allowed in path…
- encountered object type with a summary, but no description
- no description nor summary property
- no target service defined in the file
- unexpected number of yaml nodes
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/270c1aa74c88633d.
Report an issue: GitHub.
Appendix: source
Thrown at protoc-gen-openapiv2/internal/genopenapi/template.go:1625
}
// extract any constraints specified in the path placeholders into ECMA regular expressions
pathParamRegexpMap := partsToRegexpMap(parts)
// Keep track of path parameter overrides
pathParamNames := make(map[string]string)
for _, parameter := range pathParams {
var paramType, paramFormat, desc, collectionFormat, schemaPattern string
var defaultValue interface{}
var example RawExample
var enumNames interface{}
var items *openapiItemsObject
var minItems *int
var extensions []extension
switch pt := parameter.Target.GetType(); pt {
case descriptorpb.FieldDescriptorProto_TYPE_GROUP, descriptorpb.FieldDescriptorProto_TYPE_MESSAGE:
if descriptor.IsWellKnownType(parameter.Target.GetTypeName()) {
if parameter.IsRepeated() {
return errors.New("only primitive and enum types are allowed in repeated path parameters")
}
schema := schemaOfField(parameter.Target, reg, customRefs)
paramType = schema.Type
paramFormat = schema.Format
desc = schema.Description
defaultValue = schema.Default
example = schema.Example
schemaPattern = schema.Pattern
extensions = schema.extensions
} else {
return errors.New("only primitive and well-known types are allowed in path parameters")
}
case descriptorpb.FieldDescriptorProto_TYPE_ENUM:
enum, err := reg.LookupEnum("", parameter.Target.GetTypeName())
if err != nil {
return err
}
paramType = "string"View on GitHub (pinned to a58a4436a3)