{"record":{"id":"1a7d18e01cc5fbe8","repo":"grpc/grpc-go","slug":"external-processor-returned-unexpected-status-v-f-1a7d18","errorCode":null,"errorMessage":"external processor returned unexpected status %v for request headers, expected %v","messagePattern":"external processor returned unexpected status (.+?) for request headers, expected (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":1721,"sourceCode":"\t\treturn false\n\t}\n\tif resp.GetRequestDrain() {\n\t\tcs.triggerBypass()\n\t}\n\tif resp.GetImmediateResponse() != nil {\n\t\tcs.handleImmediateResponse(resp.GetImmediateResponse(), newStream, opts)\n\t\treturn false\n\t}\n\n\theader := resp.GetRequestHeaders()\n\tif header == nil {\n\t\terr := fmt.Errorf(\"external processor returned an unexpected message type %T, expected request headers response\", resp.GetResponse())\n\t\tcs.handleHeaderError(err, newStream, opts)\n\t\treturn false\n\t}\n\t// Check if status in header response is CONTINUE; if not, fail the stream.\n\tif status := header.GetResponse().GetStatus(); status != v3procservicepb.CommonResponse_CONTINUE {\n\t\tcs.handleHeaderError(fmt.Errorf(\"external processor returned unexpected status %v for request headers, expected %v\", status, v3procservicepb.CommonResponse_CONTINUE), newStream, opts)\n\t\treturn false\n\t}\n\t// Mutate the outgoing headers with additions and removals received from the\n\t// external processor.\n\toutgoingMD, _ := metadata.FromOutgoingContext(ctx)\n\tif outgoingMD == nil {\n\t\toutgoingMD = metadata.MD{}\n\t}\n\tif err = cs.applyMutations(header.GetResponse().GetHeaderMutation(), outgoingMD); err != nil {\n\t\tcs.handleHeaderError(err, newStream, opts)\n\t\treturn false\n\t}\n\tdataplaneCtx := metadata.NewOutgoingContext(ctx, outgoingMD)\n\tif err = cs.createDataplaneStream(dataplaneCtx, newStream, opts); err != nil {\n\t\treturn false\n\t}\n\treturn true\n}","sourceCodeStart":1703,"sourceCodeEnd":1739,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/httpfilter/extproc/ext_proc.go#L1703-L1739","documentation":"In processInitialHeaders (ext_proc.go:1720), the CommonResponse.Status of a request headers response must be CommonResponse_CONTINUE. Any other value is rejected because the client filter only supports continuing the request through the dataplane at this phase; aborting must use an immediate_response instead.","triggerScenarios":"External processor returns a request_headers response whose response.status is set to a value other than CONTINUE (e.g., a numeric default of 0 in some implementations that maps to a non-CONTINUE enum value, or an explicit custom status).","commonSituations":"Server-side bug defaulting the status field, or a server attempting to short-circuit a request by setting a non-CONTINUE status on the headers response rather than using an immediate_response.","solutions":["Set CommonResponse.Status = CommonResponse_CONTINUE on every request_headers response.","To short-circuit the request, send an immediate_response instead of mutating the headers response status.","Audit the server response builder to ensure status is explicitly initialized."],"exampleFix":"// before\n&procpb.HeadersResponse{Response: &procpb.CommonResponse{ /* status unset */ }}\n\n// after\n&procpb.HeadersResponse{Response: &procpb.CommonResponse{Status: procpb.CommonResponse_CONTINUE}}","handlingStrategy":"validation","validationCode":"// Server-side: always set CONTINUE on header responses\nfunc headerResponse() *procpb.HeadersResponse {\n    return &procpb.HeadersResponse{Response: &procpb.CommonResponse{Status: procpb.CommonResponse_CONTINUE}}\n}","typeGuard":null,"tryCatchPattern":"// Client-side: surfaces as codes.Internal.\nif st, ok := status.FromError(err); ok && strings.Contains(st.Message(), \"unexpected status\") {\n    // server set a non-CONTINUE status; fix the server\n}","preventionTips":["Never set a non-CONTINUE status on header/body responses; use immediate_response to abort.","Default the CommonResponse.Status to CONTINUE in the server response builder."],"tags":["extproc","grpc","protocol","xds","external-processor"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}