{"record":{"id":"8d1ff03f056e1ea0","repo":"dotnet/yarp","slug":"the-request-cannot-be-forwarded-the-response-has","errorCode":null,"errorMessage":"The request cannot be forwarded, the response has already started","messagePattern":"The request cannot be forwarded, the response has already started","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ReverseProxy/Forwarder/HttpForwarder.cs","lineNumber":112,"sourceCode":"        => SendAsync(context, destinationPrefix, httpClient, requestConfig, transformer, CancellationToken.None);\n\n    public async ValueTask<ForwarderError> SendAsync(\n        HttpContext context,\n        string destinationPrefix,\n        HttpMessageInvoker httpClient,\n        ForwarderRequestConfig requestConfig,\n        HttpTransformer transformer,\n        CancellationToken cancellationToken)\n    {\n        ArgumentNullException.ThrowIfNull(context);\n        ArgumentNullException.ThrowIfNull(destinationPrefix);\n        ArgumentNullException.ThrowIfNull(httpClient);\n        ArgumentNullException.ThrowIfNull(requestConfig);\n        ArgumentNullException.ThrowIfNull(transformer);\n\n        if (RequestUtilities.IsResponseSet(context.Response))\n        {\n            throw new InvalidOperationException(\"The request cannot be forwarded, the response has already started\");\n        }\n\n        // HttpClient overload for SendAsync changes response behavior to fully buffered which impacts performance\n        // See discussion in https://github.com/dotnet/yarp/issues/458\n        if (httpClient is HttpClient)\n        {\n            throw new ArgumentException($\"The http client must be of type HttpMessageInvoker, not HttpClient\", nameof(httpClient));\n        }\n\n        // \"http://a\".Length = 8\n        if (destinationPrefix is null || destinationPrefix.Length < 8)\n        {\n            throw new ArgumentException(\"Invalid destination prefix.\", nameof(destinationPrefix));\n        }\n\n        ForwarderTelemetry.Log.ForwarderStart(destinationPrefix);\n\n        var activityCancellationSource = ActivityCancellationTokenSource.Rent(requestConfig?.ActivityTimeout ?? DefaultTimeout, context.RequestAborted, cancellationToken);","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/ReverseProxy/Forwarder/HttpForwarder.cs#L94-L130","documentation":"Thrown by HttpForwarder.SendAsync when the response has already started (headers sent / body written) on the HttpContext. Once the response has started, YARP cannot replace it with the destination's response, so forwarding is impossible. The check uses RequestUtilities.IsResponseSet.","triggerScenarios":"A middleware or endpoint writes to context.Response (status, headers, body) before the forwarder runs. Calling SendAsync after an error handler or middleware that already produced output.","commonSituations":"Exception-handling middleware writes a response then calls the forwarder. Authentication/authorization middleware sets a 401 then continues. Custom logging middleware writes diagnostics to the response.","solutions":["Ensure no middleware writes to the response before HttpForwarder.SendAsync runs.","Short-circuit (return) after any response write instead of continuing to the forwarder.","Check context.Response.HasStarted before invoking the forwarder and handle gracefully."],"exampleFix":"// before\ncontext.Response.StatusCode = 401;\nawait forwarder.SendAsync(context, address, client, reqConfig, transformer, ct); // throws\n// after\ncontext.Response.StatusCode = 401;\nreturn; // do not forward","handlingStrategy":"validation","validationCode":"if (RequestUtilities.IsResponseSet(context.Response))\n{\n    // response already started; cannot forward\n    return;\n}","typeGuard":"static bool CanStillForward(HttpContext ctx) => !RequestUtilities.IsResponseSet(ctx.Response);","tryCatchPattern":"try { await forwarder.SendAsync(context, address, client, reqConfig, transformer, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"response has already started\"))\n{ logger.LogWarning(\"Cannot forward; response already started.\"); }","preventionTips":["Do not write to context.Response before forwarding.","Short-circuit (return) after any response write.","Check HasStarted before invoking the forwarder."],"tags":["forwarder","response-started","middleware","pipeline-ordering"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}