grpc/grpc-go · error

extauthz: empty grpc_service provided in config %v

Error message

extauthz: empty grpc_service provided in config %v

What it means

Raised by ParseFilterConfig (ext_authz.go:103) after the ExtAuthz proto is successfully unmarshaled but its grpc_service field is unset (nil). External authorization requires a backend gRPC service to send Check requests to, so a config with no grpc_service is unusable and the resource is rejected.

Source

Thrown at internal/xds/httpfilter/ext_authz/ext_authz.go:103

func grpcStatusCode(httpStatus int32) codes.Code {
	if code, ok := transport.HTTPStatusConvTab[int(httpStatus)]; ok {
		return code
	}
	return codes.Unknown
}

func (builder) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) {
	m, ok := cfg.(*anypb.Any)
	if !ok {
		return nil, fmt.Errorf("extauthz: error parsing config %v: unknown type %T, want *anypb.Any", cfg, cfg)
	}
	msg := new(v3extauthzpb.ExtAuthz)
	if err := m.UnmarshalTo(msg); err != nil {
		return nil, fmt.Errorf("extauthz: failed to unmarshal config: %v", err)
	}

	if msg.GetGrpcService() == nil {
		return nil, fmt.Errorf("extauthz: empty grpc_service provided in config %v", cfg)
	}
	server, err := parseGRPCServiceConfig(msg.GetGrpcService())
	if err != nil {
		return nil, fmt.Errorf("extauthz: failed to parse grpc_service: %v", err)
	}

	filterEnabled, err := parseFilterEnabled(msg.GetFilterEnabled())
	if err != nil {
		return nil, err
	}

	var denyAtDisable bool
	if denyAtDisableFlag := msg.GetDenyAtDisable(); denyAtDisableFlag != nil {
		if denyAtDisableFlag.GetDefaultValue() == nil {
			return nil, fmt.Errorf("extauthz: missing default_value in deny_at_disable")
		}
		denyAtDisable = denyAtDisableFlag.GetDefaultValue().GetValue()
	}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Add a grpc_service block to the ext_authz filter config in your control-plane/LDS resource (gRPC's implementation requires the gRPC variant, not http_service).
  2. Verify the grpc_service uses the google_grpc target specifier with a non-empty target_uri, since parseGRPCServiceConfig may reject envoy_grpc.
  3. Re-apply the listener and confirm the xDS resource is ACKed (no NACK) by the gRPC client.

Example fix

// before
//   ext_authz: { }   // grpc_service omitted -> error 361
//
// after
//   ext_authz: {
//     grpc_service: {
//       google_grpc: { target_uri: "authz-server:9091" }
//     }
//   }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the ExtAuthz config carries a grpc_service (ext_authz.go:102-104).
func ensureGrpcService(cfg *v3extauthzpb.ExtAuthz) error {
    if cfg.GetGrpcService() == nil {
        return fmt.Errorf("ext_authz: grpc_service must be set")
    }
    return nil
}

Prevention

When it happens

Trigger: An LDS HTTP filter typed_config that unmarshals to a valid ExtAuthz whose oneof Services is left unset, i.e. msg.GetGrpcService() == nil at ext_authz.go:102.

Common situations: An Envoy filter config that only sets http_service (not yet supported by gRPC's ext_authz) and omits grpc_service; a control-plane template with a typo or a conditional that drops the grpc_service block; a partially-rendered config during a rollout.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/ba6b3fb28b7c85c7. Report an issue: GitHub.