{"record":{"id":"da7c11da4d21dea9","repo":"grpc/grpc-go","slug":"external-processor-unexpectedly-sent-response-head","errorCode":null,"errorMessage":"external processor unexpectedly sent response headers when response header processing is disabled","messagePattern":"external processor unexpectedly sent response headers when response header processing is disabled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":1303,"sourceCode":"\t\t\t// response body message, fail the RPC.\n\t\t\tif cs.config.processingModes.responseTrailerMode == modeSend && cs.responseTrailerReady.HasFired() {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor sent response body after response trailers were already processed\"))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tstreamedResp, ok := cs.validateBodyResponse(resp.GetResponseBody())\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif streamedResp.GetEndOfStream() {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor unexpectedly set end of stream in response body mutation\"))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcs.mutatedRespBuffer.Put(streamedResp)\n\n\t\tcase resp.GetResponseHeaders() != nil:\n\t\t\tif cs.config.processingModes.responseHeaderMode == modeSkip {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor unexpectedly sent response headers when response header processing is disabled\"))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif !cs.responseHeaderSent.Load() {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor sent response headers before response headers were sent to it\"))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif cs.responseHeadersReady.HasFired() {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor unexpectedly sent duplicate response headers after response headers were already processed\"))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\theader := resp.GetResponseHeaders()\n\t\t\t// Check if the status in the header response is CONTINUE; if not, fail\n\t\t\t// the stream.\n\t\t\tif status := header.GetResponse().GetStatus(); status != v3procservicepb.CommonResponse_CONTINUE {\n\t\t\t\tcs.failProcStream(fmt.Errorf(\"external processor returned unexpected status %v for response headers, expected %v\", status, v3procservicepb.CommonResponse_CONTINUE))\n\t\t\t\treturn\n\t\t\t}","sourceCodeStart":1285,"sourceCodeEnd":1321,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/httpfilter/extproc/ext_proc.go#L1285-L1321","documentation":"Raised when the server sends a response_headers response while responseHeaderMode is modeSkip. The client never asked to process response headers, so a response-headers mutation is a protocol violation and the proc stream is failed.","triggerScenarios":"processing_mode.response_header_mode == SKIP (or defaulted to SKIP via per-route override) and the server emits a ProcessingResponse.response_headers.","commonSituations":"Server always acks response headers regardless of mode. Per-route override disabled header processing for a route but the server is shared and assumes headers are on.","solutions":["Set processing_mode.response_header_mode to SEND if you want header processing.","Otherwise fix the server to not emit response_headers when the negotiated ProtocolConfiguration implies headers are skipped.","Enable failure_mode_allow to bypass while fixing."],"exampleFix":"// before\nprocessing_mode:\n  response_header_mode: SKIP   # server sends response_headers anyway\n\n// after\nprocessing_mode:\n  response_header_mode: SEND","handlingStrategy":"validation","validationCode":"// Server: suppress response_headers when the negotiated header mode is SKIP.\nfunc maybeResponseHeaders(mode v3procfilterpb.ProcessingMode_HeaderSendMode, resp *pb.ProcessingResponse) *pb.ProcessingResponse {\n    if mode == v3procfilterpb.ProcessingMode_SKIP && resp.GetResponseHeaders() != nil {\n        return nil\n    }\n    return resp\n}","typeGuard":null,"tryCatchPattern":"// Client: failure_mode_allow -> bypass.","preventionTips":["Set response_header_mode SEND iff the server will ack headers.","Enable failure_mode_allow to tolerate mismatches."],"tags":["extproc","protocol-violation","processing-mode","response-headers","server-bug"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}