grpc/grpc-go · error

extproc: failed to unmarshal override %v: %v

Error message

extproc: failed to unmarshal override %v: %v

What it means

Raised by ParseFilterConfigOverride when the *anypb.Any decodes fine as a wrapper but UnmarshalTo into v3procfilterpb.ExtProcPerRoute fails. The bytes inside the Any either do not match the ExtProcPerRoute schema or carry a mismatched/incompatible type URL, so the per-route override is rejected.

Source

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

		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())
		if err != nil {
			return nil, fmt.Errorf("extproc: failed to parse grpc_service: %v", err)
		}
		serverOpt = optional.New(server)

View on GitHub (pinned to 03255a9237)

Solutions

  1. Confirm the Any's type_url equals type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute and matches the client's go-control-plane module version.
  2. Re-serialize the override with the exact ExtProcPerRoute proto the client was built against and redeploy the LDS resource.
  3. If a different filter's override was attached by mistake, move it under the correct per-filter key in the RouteAction.typed_per_filter_config map.

Example fix

// before: control plane emits an override under the wrong @type
{"@type":"type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ProcessingMode", ...}

// after
{"@type":"type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute", "overrides":{...}}
Defensive patterns

Strategy: validation

Validate before calling

// Verify type URL + round-trip before relying on the override.
func validateOverrideAny(a *anypb.Any) error {
    want := "type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute"
    if a.GetTypeUrl() != want {
        return fmt.Errorf("wrong type_url %q, want %q", a.GetTypeUrl(), want)
    }
    m := new(v3procfilterpb.ExtProcPerRoute)
    return a.UnmarshalTo(m)
}

Prevention

When it happens

Trigger: LDS typed_per_filter_config carries an Any whose @type is not type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute, or whose payload is corrupt/truncated, or that was serialized with an incompatible proto version of ExtProcPerRoute.

Common situations: Control plane and client use different versions of go-control-plane so the ExtProcPerRoute field layout differs. A typo in the @type URL. A per-route config meant for a different filter (e.g. router, rbac) accidentally attached under the extproc key.

Related errors


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