grpc-ecosystem/grpc-gateway · error
only primitive and well-known types are allowed in path para
Error message
only primitive and well-known types are allowed in path parameters
What it means
renderServices requires that path parameters be primitive types, enums, or protobuf well-known types. When a non-repeated path parameter targets a GROUP or MESSAGE field that is not a well-known type (e.g. google.protobuf.Timestamp, wrappers), the generator returns "only primitive and well-known types are allowed in path parameters" because such a message cannot be rendered as a valid OpenAPI path parameter.
Source
Thrown at protoc-gen-openapiv2/internal/genopenapi/template.go:1636
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"
paramFormat = ""
enumNames = listEnumNames(reg, enum)
if reg.GetEnumsAsInts() {
paramType = "integer"
paramFormat = ""
enumNames = listEnumNumbers(reg, enum)
}
schema := schemaOfField(parameter.Target, reg, customRefs)
desc = schema.Description
defaultValue = schema.DefaultView on GitHub (pinned to a58a4436a3)
Solutions
- Reference a primitive or enum field in the path template instead of the message, e.g. `{book_id}` where book_id is int64/string, or `{book.id}` for a scalar subfield.
- Move the message field out of the path into the request body (`body: "*"` or a body field).
- If you intended a wrapper, use the actual well-known type (google.protobuf.StringValue, Timestamp, etc.) that IsWellKnownType recognizes.
- For IDs, flatten them: put `string id` on the request message and bind `{id}` in the path.
Example fix
// before
rpc GetBook(BookRequest) ... // path: "/v1/{book=**}" where book is message Book
// after
rpc GetBook(GetBookRequest) ... // message { string book_id = 1; } path: "/v1/{book_id}" Defensive patterns
Strategy: validation
Validate before calling
for _, p := range binding.PathParams {
t := p.Target.GetType()
if (t == descriptorpb.FieldDescriptorProto_TYPE_MESSAGE || t == descriptorpb.FieldDescriptorProto_TYPE_GROUP) && !descriptor.IsWellKnownType(p.Target.GetTypeName()) {
return fmt.Errorf("path param %q must be a primitive, enum, or well-known type", p.Target.GetName())
}
} Type guard
func validPathParam(f *descriptor.Field) bool {
switch f.Target.GetType() {
case descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, descriptorpb.FieldDescriptorProto_TYPE_GROUP:
return descriptor.IsWellKnownType(f.Target.GetTypeName())
default:
return true
}
} Try / catch
if err := applyTemplate(...); err != nil {
if strings.Contains(err.Error(), "well-known types are allowed in path parameters") {
return fmt.Errorf("rewrite the http rule path to use a scalar field: %w", err)
}
return err
} Prevention
- Bind path variables only to primitive/enum fields or explicit subfields like {msg.id}.
- Avoid proto2 groups in HTTP bindings entirely.
- Review google.api.http annotations during proto code review.
When it happens
Trigger: A google.api.http path template referencing a message-typed field that is not a well-known type, e.g. `get: "/v1/{book.title}"` where the referenced field is a custom message, or a group field in the path.
Common situations: Pointing a path variable at a nested message/submessage instead of a scalar; using proto2 groups; copying bindings from another service whose field was a well-known wrapper; protos not importing google/protobuf/wrappers.proto or timestamp.proto so the field is a custom message.
Related errors
- only primitive and enum types are allowed in repeated path p
- no target service defined in the file
- unexpected number of yaml nodes
- encountered object type with a summary, but no description
- no description nor summary property
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/da201566cec99a4a.
Report an issue: GitHub.