Skip to content

ProblemDetails returns unexpected 500 status for HEAD requests #214

@thomas-darling

Description

@thomas-darling

In an ASP.NET Core 9 project using the ProblemDetails middleware, specifically services.AddProblemDetailsConventions() and services.AddProblemDetails(), when calling return this.NotFound() in a controller action for a HEAD request, the client receives status 500 Not Found, which makes no sense - the expected status is 404 NotFound. I'm guessing something similar will happen when attempting to return any other error status.

I believe this happen because the ProblemDetails middleware attempts to write a response body, despite the fact that a HEAD response should never have a body - and it might be exacerbated by this recent regression in ASP.NET Core 9: dotnet/aspnetcore#59691.

The ProblemDetails middleware should maybe be fixed, so it doesn't attempt to write a response body for HEAD requests - though if the actual root cause is the regression mentioned above, it could be argued that this middleware behaves correctly, as I'd assume attempting to write the response body is one way to ensure the correct content-length header is set. I guess the alternative would be to generate the response body, but not write it to the stream, and only set the content-length header.

In the meantime, the workaround appears to be to add middleware that swallows attempts to write to the response body for a HEAD request. This should be added before any other middleware that might write to the body stream.

applicationBuilder.Use(async (ctx, next) =>
{
    // For HEAD requests, suppress any response body writes from downstream middleware.
    if (HttpMethods.IsHead(ctx.Request.Method))
    {
        var originalBody = ctx.Response.Body;
        ctx.Response.Body = Stream.Null;

        try
        {
            await next();
        }
        finally
        {
            // Restore the original stream so upstream middleware sees what it expects.
            ctx.Response.Body = originalBody;
        }
    }
    else
    {
        await next();
    }
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions