grpc/grpc-go · error

extproc: error parsing override %v: unknown type %T, want *a

Error message

extproc: error parsing override %v: unknown type %T, want *anypb.Any

What it means

Raised by ParseFilterConfigOverride when the per-route override proto passed to the extproc filter builder is not a *anypb.Any. The XDS layer is expected to always hand the filter a decoded *anypb.Any; this assertion enforces that contract. Hitting it means the data path feeding filter overrides deviated from the registered type-URL contract.

Source

Thrown at internal/xds/httpfilter/extproc/ext_proc.go:176

	return baseConfig{
		processingModes:          processingModesFromProto(msg.GetProcessingMode()),
		requestAttributes:        msg.GetRequestAttributes(),
		responseAttributes:       msg.GetResponseAttributes(),
		disableImmediateResponse: msg.GetDisableImmediateResponse(),
		observabilityMode:        msg.GetObservabilityMode(),
		failureModeAllow:         msg.GetFailureModeAllow(),
		server:                   server,
		mutationRules:            mutationRules,
		allowedHeaders:           allowedHeaders,
		disallowedHeaders:        disallowedHeaders,
		deferredCloseTimeout:     deferredCloseTimeout,
	}, nil
}

func (builder) ParseFilterConfigOverride(ov proto.Message) (httpfilter.FilterConfig, error) {
	m, ok := ov.(*anypb.Any)
	if !ok {
		return nil, fmt.Errorf("extproc: error parsing override %v: unknown type %T, want *anypb.Any", ov, ov)
	}
	msg := new(v3procfilterpb.ExtProcPerRoute)
	if err := m.UnmarshalTo(msg); err != nil {
		return nil, fmt.Errorf("extproc: failed to unmarshal override %v: %v", ov, err)
	}
	override := msg.GetOverrides()

	var processingModesOpt optional.Optional[processingModes]
	if pm := override.GetProcessingMode(); pm != nil {
		if err := validateBodyProcessingMode(pm); err != nil {
			return nil, err
		}
		processingModesOpt = optional.New(processingModesFromProto(pm))
	}

	var serverOpt optional.Optional[xdsresource.GRPCServiceConfig]
	if override.GetGrpcService() != nil {
		server, err := iextproc.ParseGRPCServiceConfig(override.GetGrpcService())

View on GitHub (pinned to 03255a9237)

Solutions

  1. Wrap the per-route override message in *anypb.Any before passing it to ParseFilterConfigOverride: anypb.New(&v3procfilterpb.ExtProcPerRoute{...}).
  2. If this surfaces from real xDS traffic, verify the LDS route configuration encodes typed_per_filter_config as a typed Struct/Any with @type set to type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute.
  3. Check that no other httpfilter.Register call shadowed extproc's builder, which can corrupt type dispatch.

Example fix

// before
m := &v3procfilterpb.ExtProcPerRoute{Overrides: &v3procfilterpb.ExtProcPerRoute_Overrides{...}}
cfg, err := builder{}.ParseFilterConfigOverride(m)

// after
a, _ := anypb.New(&v3procfilterpb.ExtProcPerRoute{Overrides: &v3procfilterpb.ExtProcPerRoute_Overrides{...}})
cfg, err := builder{}.ParseFilterConfigOverride(a)
Defensive patterns

Strategy: type-guard

Validate before calling

// The XDS layer should always pass *anypb.Any; guard in code that wraps the builder.
func safeParseOverride(b httpfilter.FilterBuilder, ov proto.Message) (httpfilter.FilterConfig, error) {
    if _, ok := ov.(*anypb.Any); !ok {
        return nil, fmt.Errorf("override must be *anypb.Any, got %T", ov)
    }
    return b.ParseFilterConfigOverride(ov)
}

Type guard

func isAny(m proto.Message) bool { _, ok := m.(*anypb.Any); return ok }

Prevention

When it happens

Trigger: ParseFilterConfigOverride is called (during LDS/xDS resource decoding) with a proto.Message whose concrete type is not *anypb.Any — e.g. a test invoking the builder directly with a *v3procfilterpb.ExtProcPerRoute instead of wrapping it in an Any, or a non-conformant custom httpfilter plumbing that forwards the unwrapped message.

Common situations: Unit/integration tests that call ParseFilterConfigOverride directly without wrapping the override in anypb.New(). A forked or custom xDS client that decodes typed_per_filter_config into the inner message type before handing it to the builder. A filter-registry bug that re-dispatches the wrong concrete type.

Related errors


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