grpc/grpc-go · error
external processor returned unexpected status %v for respons
Error message
external processor returned unexpected status %v for response headers, expected %v
What it means
Raised when the server's response_headers message carries a CommonResponse status other than CONTINUE. For response headers the gRPC extproc client only permits CONTINUE (apply mutations and continue the stream); any other status is rejected and the proc stream is failed.
Source
Thrown at internal/xds/httpfilter/extproc/ext_proc.go:1319
case resp.GetResponseHeaders() != nil:
if cs.config.processingModes.responseHeaderMode == modeSkip {
cs.failProcStream(fmt.Errorf("external processor unexpectedly sent response headers when response header processing is disabled"))
return
}
if !cs.responseHeaderSent.Load() {
cs.failProcStream(fmt.Errorf("external processor sent response headers before response headers were sent to it"))
return
}
if cs.responseHeadersReady.HasFired() {
cs.failProcStream(fmt.Errorf("external processor unexpectedly sent duplicate response headers after response headers were already processed"))
return
}
header := resp.GetResponseHeaders()
// Check if the status in the header response is CONTINUE; if not, fail
// the stream.
if status := header.GetResponse().GetStatus(); status != v3procservicepb.CommonResponse_CONTINUE {
cs.failProcStream(fmt.Errorf("external processor returned unexpected status %v for response headers, expected %v", status, v3procservicepb.CommonResponse_CONTINUE))
return
}
if err = cs.applyMutations(header.GetResponse().GetHeaderMutation(), cs.responseHeader); err != nil {
cs.failProcStream(err)
return
}
// Signal that the response header is modified and ready to be sent to the
// client, so that if there is any buffered response body, it can be sent
// after the header.
cs.fireResponseHeadersReady()
case resp.GetResponseTrailers() != nil:
if cs.config.processingModes.responseTrailerMode == modeSkip {
cs.failProcStream(fmt.Errorf("external processor unexpectedly sent response trailers when response trailer processing is disabled"))
return
}
if !cs.trailerSent.Load() {
cs.failProcStream(fmt.Errorf("external processor sent response trailers before response trailers were sent to it"))View on GitHub (pinned to 03255a9237)
Solutions
- Set response_headers.response.status = CONTINUE for every response-headers message.
- If the server needs to abort/replace the response, use immediate_response instead of a non-CONTINUE header status.
- Enable failure_mode_allow to bypass while fixing.
Example fix
// before
stream.Send(&pb.ProcessingResponse{ResponseHeaders:&pb.HeadersResponse{Response:&pb.CommonResponse{Status: pb.CommonResponse_RESET_STREAM, HeaderMutation: m}}})
// after
stream.Send(&pb.ProcessingResponse{ResponseHeaders:&pb.HeadersResponse{Response:&pb.CommonResponse{Status: pb.CommonResponse_CONTINUE, HeaderMutation: m}}}) Defensive patterns
Strategy: validation
Validate before calling
// Server: force CONTINUE on response-headers responses. resp.Response.Status = pb.CommonResponse_CONTINUE
Try / catch
// Client: failure_mode_allow -> bypass.
Prevention
- Use immediate_response (not header status) to abort or replace the response.
- Always set response_headers.response.status = CONTINUE.
When it happens
Trigger: The server sets response_headers.response.status to something other than CommonResponse_CONTINUE (e.g. it tries to use the Envoy-style RESET_STREAM/ERROR or an immediate-response status on response headers).
Common situations: Server ported from Envoy ext_proc where header responses can carry other statuses. Server attempts to short-circuit the response via the header message instead of using the immediate_response field.
Related errors
- external processor sent response body before sending respons
- external processor unexpectedly sent response headers when r
- external processor sent response headers before response hea
- external processor unexpectedly sent duplicate response head
- external processor unexpectedly sent request body when reque
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/9ad6cdf56c6a1681.
Report an issue: GitHub.