Skip to content

ProblemDetails payload differs between Development and custom environment for JSON model-binding failure (Minimal APIs + AddProblemDetails + UseExceptionHandler) #63331

@vadimt2

Description

@vadimt2

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When a Minimal API endpoint binds a request body to a record with an int property and the client sends an invalid value (e.g., "a"), the response body for HTTP 400 differs between environments, despite using AddProblemDetails() and UseExceptionHandler().

  • In Development environment, the response includes exception details with "type": "BadHttpRequestException" and a descriptive detail.

  • In a custom environment (e.g., Test), the response is a generic RFC 9110 problem with "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1" and no detail.

This inconsistency makes it difficult to rely on a stable ProblemDetails shape across environments for client handling and observability.

Expected Behavior

In test Environment:
{
"type": "BadHttpRequestException",
"title": "An error occurred",
"status": 400,
"detail": "Failed to read parameter "TestRequest request" from the request body as JSON.",
"instance": "POST /weatherforecast"
}

Steps To Reproduce

You can clone my repo and just change the Environment for development and the second time for test.
https://github.com/vadimt2/net8-CustomException-issue

1. Create a new **.NET 8 Minimal API** project:

   ```bash
   dotnet new web -n ReproApp
   cd ReproApp
  1. Replace Program.cs with:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    builder.Services.AddProblemDetails();
    builder.Services.AddExceptionHandler<ExceptionHandler>();
    
    var app = builder.Build();
    
    if (app.Environment.IsDevelopment() || app.Environment.IsEnvironment("test"))
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    app.UseExceptionHandler();
    app.UseStatusCodePages();
    
    app.MapPost("/weatherforecast", (TestRequest request) =>
    {
        return Results.Ok();
    });
    
    app.Run();
    
    public record TestRequest(int number);
    
    class ExceptionHandler : Microsoft.AspNetCore.Diagnostics.IExceptionHandler
    {
        public ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
            => new(false);
    }
  2. In Properties/launchSettings.json, add two profiles that differ only in ASPNETCORE_ENVIRONMENT:

    "profiles": {
      "https (Development)": {
        "commandName": "Project",
        "applicationUrl": "https://localhost:7221;http://localhost:5041",
        "environmentVariables": {
          "ASPNETCORE_ENVIRONMENT": "Development"
        }
      },
      "https (Test)": {
        "commandName": "Project",
        "applicationUrl": "https://localhost:7221;http://localhost:5041",
        "environmentVariables": {
          "ASPNETCORE_ENVIRONMENT": "Test"
        }
      }
    }
  3. Run the app with the Development profile and send:

    POST https://localhost:7221/weatherforecast
    Content-Type: application/json
    
    { "number": "a" }

    Response:

    {
      "type": "BadHttpRequestException",
      "title": "An error occurred",
      "status": 400,
      "detail": "Failed to read parameter \"TestRequest request\" from the request body as JSON.",
      "instance": "POST /weatherforecast"
    }
  4. Run the app with the Test profile and send the same request:

    Response:

    {
      "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
      "title": "Bad Request",
      "status": 400
    }

Exceptions (if any)

No response

.NET Version

8.0.18

Anything else?

please clone the repo
https://github.com/vadimt2/net8-CustomException-issue

use swagger for testing

{
"number": "a"
}

send a request with: Development and Test
you will see a different result, both of the results should be the same as Development

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-problem-details

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions