grpc/grpc-go · error

extproc: incorrect config type provided (%T): %v

Error message

extproc: incorrect config type provided (%T): %v

What it means

Raised by BuildClientInterceptor when the base filter config handed to it is not the internal baseConfig type produced by ParseFilterConfig. The builder pipeline guarantees that ParseFilterConfig returns a baseConfig; any other concrete type indicates the httpfilter framework handed back an unexpected value.

Source

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

	return &clientFilter{
		metricsRecorder: opts.MetricsRecorder,
		target:          opts.Target,
	}
}

var _ httpfilter.ClientFilterBuilder = builder{}

type clientFilter struct {
	metricsRecorder estats.MetricsRecorder
	target          string
}

func (clientFilter) Close() {}

func (cf *clientFilter) BuildClientInterceptor(base, override httpfilter.FilterConfig) (httpfilter.ClientInterceptor, error) {
	b, ok := base.(baseConfig)
	if !ok {
		return nil, fmt.Errorf("extproc: incorrect config type provided (%T): %v", base, base)
	}

	var ov overrideConfig
	if override != nil {
		ov, ok = override.(overrideConfig)
		if !ok {
			return nil, fmt.Errorf("extproc: incorrect override config type provided (%T): %v", override, override)
		}
	}

	config := newInterceptorConfig(b, ov)

	// Create a channel to the external processor server.
	cc, cancel, err := iextproc.CreateExtProcChannel(config.server)
	if err != nil {
		return nil, fmt.Errorf("extproc: failed to create channel to the external processor server %q: %v", config.server.TargetURI, err)
	}
	return &clientInterceptor{

View on GitHub (pinned to 03255a9237)

Solutions

  1. Ensure base originates from extproc's ParseFilterConfig (returns baseConfig) and not from another filter's builder.
  2. In tests, pass a real baseConfig value rather than a mock FilterConfig.
  3. Check for TypeURL collisions in the httpfilter registry and that the extproc builder is the one handling type type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor.

Example fix

// before (test): wrong base type
cf := clientFilter{}
cf.BuildClientInterceptor(mockConfig{}, nil)

// after
cf := clientFilter{}
cf.BuildClientInterceptor(baseConfig{server: srv, processingModes: pm}, nil)
Defensive patterns

Strategy: type-guard

Validate before calling

// In tests, assert the base config is the extproc baseConfig.
func mustBuild(cf httpfilter.ClientFilter, base, ov httpfilter.FilterConfig) (httpfilter.ClientInterceptor, error) {
    if _, ok := base.(baseConfig); !ok {
        return nil, fmt.Errorf("base not extproc baseConfig: %T", base)
    }
    return cf.BuildClientInterceptor(base, ov)
}

Type guard

func isBaseConfig(c httpfilter.FilterConfig) bool { _, ok := c.(baseConfig); return ok }

Prevention

When it happens

Trigger: BuildClientInterceptor is invoked with a base FilterConfig produced by a different filter's ParseFilterConfig (registry/type-URL collision), or a test constructs a clientFilter and calls BuildClientInterceptor with an arbitrary httpfilter.FilterConfig value.

Common situations: Two filters registered under overlapping TypeURLs. A test that fakes base config with a struct that does not equal baseConfig. A refactor of baseConfig that left an old type still being passed.

Related errors


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