grpc-ecosystem/grpc-gateway · error

only primitive and enum types are allowed in repeated path p

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.

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)

Solutions

  1. 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.
  2. Restructure the binding to pass the repeated message in the request body instead of the path.
  3. If you only need some fields, flatten them into repeated primitive fields and reference those in the path.
  4. 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

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


AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02). Data as JSON: /api/errors/270c1aa74c88633d. Report an issue: GitHub.