grpc-ecosystem/grpc-gateway · error

can't resolve OpenAPI name from %q

Error message

can't resolve OpenAPI name from %q

What it means

renderMessagesAsDefinition converts registered messages into OpenAPI definitions and must translate each message's fully-qualified name into the (possibly shortened, uniquified) OpenAPI schema name via fullyQualifiedNameToOpenAPIName. If the FQMN isn't found in the precomputed name map, generation fails with 'can't resolve OpenAPI name from %q'. It indicates the message-name resolution pass and the rendering pass saw inconsistent registry state.

Source

Thrown at protoc-gen-openapiv2/internal/genopenapi/template.go:903

			schema.AdditionalProperties = &openapiSchemaObject{}
			schema.Properties = &openapiSchemaObjectProperties{keyVal{
				Key:   "@type",
				Value: property.Value,
			}}
			break
		}
	}
}

func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap, pathParams []descriptor.Parameter) error {
	// Sort keys so that when two messages flatten to the same OpenAPI definition
	// name the winner is deterministic (last in sorted order wins) rather than
	// varying with Go's random map iteration order.
	for _, name := range slices.Sorted(maps.Keys(messages)) {
		msg := messages[name]
		swgName, ok := fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg)
		if !ok {
			return fmt.Errorf("can't resolve OpenAPI name from %q", msg.FQMN())
		}
		if skipRenderingRef(name) {
			continue
		}

		if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry {
			continue
		}
		if _, exists := d[swgName]; exists {
			grpclog.Warningf("Collision: multiple messages map to OpenAPI definition name %q; the definition will be overwritten", swgName)
		}
		var err error
		d[swgName], err = renderMessageAsDefinition(msg, reg, customRefs, pathParams)
		if err != nil {
			return err
		}
	}
	return nil

View on GitHub (pinned to a58a4436a3)

Solutions

  1. Regenerate the full API surface in a single protoc invocation so all messages are registered in the FQMN name map.
  2. Check for duplicate proto package/file names that collide in the OpenAPI name uniquifier.
  3. Verify the message's package path is consistent (no mixed casing or path aliases) across imports.
  4. Update protoc-gen-openapiv2 — this can stem from name-resolution bugs fixed in newer releases.

Example fix

// before: two protos both declare package foo.v1 with the same file basenames in different dirs, breaking name resolution
// after: make packages/files unique
// a/types.proto -> package a.v1; b/types.proto -> package b.v1
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure name resolution covers all messages before rendering:
for name := range messages {
    if _, ok := fullyQualifiedNameToOpenAPIName(name, reg); !ok {
        return fmt.Errorf("pre-check: %s missing from OpenAPI name table", name)
    }
}

Try / catch

if err := generateOpenAPI(); err != nil {
    if strings.Contains(err.Error(), "can't resolve OpenAPI name") {
        return fmt.Errorf("regenerate with the FULL proto file set: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: applyTemplate/addCustomRefs call renderMessagesAsDefinition over the collected messages map and fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg) returns ok=false — the message was collected for rendering but its name was never registered during the FQMN→OpenAPI-name resolution (resolveFullyQualifiedNameToOpenAPINames) pass.

Common situations: Messages pulled in from dependency files processed inconsistently across multiple protoc runs; duplicate or conflicting package/file names breaking FQMN mapping; plugin bugs with unusual naming (deeply nested messages across packages) that the name-uniquifier skipped.

Related errors


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