grpc-ecosystem/grpc-gateway · error

selector %q in %v must specify a single service method witho

Error message

selector %q in %v must specify a single service method without wildcards

What it means

registerHTTPRulesFromGrpcAPIService rejects any HttpRule selector containing '*' or spaces (and thus empty selectors), because selectors in gRPC API Configuration must name exactly one fully-qualified service method. Wildcard or multi-method selectors cannot be resolved to a single registration target.

Source

Thrown at internal/descriptor/grpc_api_configuration.go:47

	serviceConfiguration := apiconfig.GrpcAPIService{}
	if err := unmarshaler.Unmarshal(jsonContents, &serviceConfiguration); err != nil {
		return nil, fmt.Errorf("failed to parse gRPC API Configuration from YAML in %q: %w", yamlSourceLogName, err)
	}

	return &serviceConfiguration, nil
}

func registerHTTPRulesFromGrpcAPIService(registry *Registry, service *apiconfig.GrpcAPIService, sourceLogName string) error {
	if service.Http == nil {
		// Nothing to do
		return nil
	}

	for _, rule := range service.Http.GetRules() {
		selector := "." + strings.Trim(rule.GetSelector(), " ")
		if strings.ContainsAny(selector, "*, ") {
			return fmt.Errorf("selector %q in %v must specify a single service method without wildcards", rule.GetSelector(), sourceLogName)
		}

		registry.AddExternalHTTPRule(selector, rule)
	}

	return nil
}

// LoadGrpcAPIServiceFromYAML loads a gRPC API Configuration from the given YAML file
// and registers the HttpRule descriptions contained in it as externalHTTPRules in
// the given registry. This must be done before loading the proto file.
//
// You can learn more about gRPC API Service descriptions from Google's documentation
// at https://cloud.google.com/endpoints/docs/grpc/grpc-service-config
//
// Note that for the purposes of the gateway generator we only consider a subset of all
// available features google supports in their service descriptions.
func (r *Registry) LoadGrpcAPIServiceFromYAML(yamlFile string) error {

View on GitHub (pinned to a58a4436a3)

Solutions

  1. Replace the wildcard with explicit selectors — one rule per fully-qualified method, e.g. selector: mypkg.MyService.MethodA (one entry per method)
  2. Trim whitespace from selectors in generated configs; remove any spaces inside the selector string
  3. If you need rules for many methods, script the config generation to enumerate methods instead of using wildcards

Example fix

// before
http:
  rules:
    - selector: mypkg.MyService.*
      get: /v1/items
// after
http:
  rules:
    - selector: mypkg.MyService.GetItem
      get: /v1/items/{id}
    - selector: mypkg.MyService.ListItems
      get: /v1/items
Defensive patterns

Strategy: validation

Validate before calling

for _, rule := range cfg.Http.Rules {
    sel := rule.GetSelector()
    if sel == "" || strings.ContainsAny(sel, "*, ") {
        return fmt.Errorf("selector %q must be a single fully-qualified method", sel)
    }
}

Type guard

func isPlainMethodSelector(sel string) bool {
    return sel != "" && !strings.ContainsAny(sel, "*, ")
}

Try / catch

if err := descriptor.LoadGrpcAPIServiceFromYAML(data, name); err != nil {
    if strings.Contains(err.Error(), "must specify a single service method") {
        grpclog.Fatalf("expand wildcard selectors in %s", name)
    }
    return err
}

Prevention

When it happens

Trigger: A YAML config http.rules entry with selector like "pkg.Service*", "pkg.*", a selector containing spaces, or an empty selector, processed via LoadGrpcAPIServiceFromYAML.

Common situations: Users expecting wildcard selector support (as in some other gRPC tooling) and writing "myapp.*" in gateway YAML; copy-paste leaving trailing spaces or an incomplete method name; template-generated configs where the method name failed to substitute.

Related errors


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