grpc/grpc-go · error
extproc: missing processing_mode in config %v
Error message
extproc: missing processing_mode in config %v
What it means
Raised by ParseFilterConfig (ext_proc.go:119) when the ExternalProcessor config unmarshals successfully but its processing_mode field is nil. ext_proc requires a processing_mode to decide which headers/bodies/trailers to forward; an absent one is rejected before validateBodyProcessingMode even runs.
Source
Thrown at internal/xds/httpfilter/extproc/ext_proc.go:119
return fmt.Errorf("extproc: invalid response body mode %v: want %q or %q", m, "NONE", "GRPC")
}
if mode.GetResponseBodyMode() == v3procfilterpb.ProcessingMode_GRPC && mode.GetResponseTrailerMode() != v3procfilterpb.ProcessingMode_SEND {
return fmt.Errorf("extproc: invalid response trailer mode %v: must be %q when response body mode is %q", mode.GetResponseTrailerMode(), "SEND", "GRPC")
}
return nil
}
func (builder) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) {
m, ok := cfg.(*anypb.Any)
if !ok {
return nil, fmt.Errorf("extproc: error parsing config %v: unknown type %T, want *anypb.Any", cfg, cfg)
}
msg := new(v3procfilterpb.ExternalProcessor)
if err := m.UnmarshalTo(msg); err != nil {
return nil, fmt.Errorf("extproc: failed to unmarshal config %v: %v", cfg, err)
}
if msg.GetProcessingMode() == nil {
return nil, fmt.Errorf("extproc: missing processing_mode in config %v", cfg)
}
if err := validateBodyProcessingMode(msg.GetProcessingMode()); err != nil {
return nil, err
}
if msg.GetGrpcService() == nil {
return nil, fmt.Errorf("extproc: empty grpc_service provided in config %v", cfg)
}
server, err := iextproc.ParseGRPCServiceConfig(msg.GetGrpcService())
if err != nil {
return nil, fmt.Errorf("extproc: failed to parse grpc_service %v", err)
}
mutationRules, err := httpfilter.HeaderMutationRulesFromProto(msg.GetMutationRules())
if err != nil {
return nil, err
}
View on GitHub (pinned to 03255a9237)
Solutions
- Add an explicit processing_mode block to the ExternalProcessor config.
- At minimum set the header/body modes you need using only NONE/GRPC (and SEND for response trailers when response body is GRPC).
- If you want all-skip behavior, still provide processing_mode with the relevant fields set to NONE/SKIP.
Example fix
// before
// external_processor: { grpc_service: { ... } } // processing_mode omitted -> error 377
//
// after
// external_processor: {
// grpc_service: { google_grpc: { target_uri: "proc:9092" } },
// processing_mode: { request_header_mode: SEND, request_body_mode: NONE,
// response_header_mode: SEND, response_body_mode: NONE }
// } Defensive patterns
Strategy: validation
Validate before calling
// Ensure processing_mode is present (ext_proc.go:118-120).
func ensureProcessingMode(cfg *v3procfilterpb.ExternalProcessor) error {
if cfg.GetProcessingMode() == nil {
return fmt.Errorf("extproc: processing_mode is required")
}
return nil
} Prevention
- Always include an explicit processing_mode in ext_proc configs — gRPC does not assume Envoy's defaults.
- Make processing_mode a required field in your control-plane schema/template.
- Lint ext_proc resources for a missing processing_mode in CI.
When it happens
Trigger: msg.GetProcessingMode() == nil at ext_proc.go:118 — the ExternalProcessor proto was provided but the processing_mode sub-message was left unset.
Common situations: A minimal ext_proc config that only sets grpc_service and omits processing_mode, assuming defaults; a control-plane template whose processing_mode block is conditionally empty; porting an Envoy config that relies on Envoy's implicit defaults (gRPC requires explicit processing_mode here).
Related errors
- extproc: invalid request body mode %v: want %q or %q
- extproc: invalid response body mode %v: want %q or %q
- extproc: invalid response trailer mode %v: must be %q when r
- extproc: error parsing config %v: unknown type %T, want *any
- extproc: failed to unmarshal config %v: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/76aa63827537417d.
Report an issue: GitHub.