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

  1. Pass all dependent proto files (where the nested message is defined) to the protoc invocation.
  2. Confirm the field's type name resolves in your proto tree (no renames/typos).
  3. Regenerate descriptors for the whole package set at once.
  4. 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

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


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