Skip to content

406 Not Accepted when returning ObjectResult with content type 'application/json; charset=utf-8' #56357

@angularsen

Description

@angularsen

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Returning ObjectResult from API action with ContentTypes = ["application/json; charset=utf-8"] results in 406 Not Accepted.

It fails to match with Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter due to the ; charset=utf-8 suffix.

By changing it to ContentTypes = ["application/json"], it returns 200 OK with JSON response as expected.

Why this happens

NewtonsoftJsonOutputFormatter.CanWriteResult returns false, because MediaTypeHeaderValue.IsSubsetOf() and MediaTypeHeaderValue.MatchesParameters() fail to recognize that Accept: application/json is compatible with Content-Type: application/json; charset=utf-8

Not sure if this is a bug or by design, but I expected it to be able to match regardless of charset - or at least if the charset matched what it would output itself.

Related issue on using IdempotentAPI to cache responses with this content type: ikyriak/IdempotentAPI#78

Sample code

[ApiController]
[Route("[controller]")]
public class FooController : ControllerBase
{
    [HttpGet("fail")]
    public IActionResult Fail()
    {
        return new ObjectResult(new
        {
            Message = """
                      This will fail with 406 Not Accepted due to unsupported response content type 'application/json; charset=utf-8':

                      Error message: 
                      No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response.
                      """
        })
        {
            ContentTypes = ["application/json; charset=utf-8"],
            StatusCode = 200
        };
    }

    [HttpGet("pass")]
    public IActionResult Pass()
    {
        return new ObjectResult(new
        {
            Message = """
                      This will succeed due to supported response content type 'application/json'.
                      """
        })
        {
            ContentTypes = ["application/json"],
            StatusCode = 200
        };
    }
}

Log output

Key log entries:

Microsoft.AspNetCore.Mvc.Infrastructure.DefaultOutputFormatterSelector[9]
Attempting to select the first output formatter in the output formatters list which supports a content type from the explicitly specified content types 'application/json; charset=utf-8'.

Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[2]
      No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response.

Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET http://localhost:5176/foo/fail - 406 0 - 154.7296ms
Full log for GET http://localhost:5176/foo/fail
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET http://localhost:5176/foo/fail - - -
dbug: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
      Wildcard detected, all requests with hosts will be allowed.
trce: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[2]
      All hosts are allowed.
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
      1 candidate(s) found for the request path '/foo/fail'
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
      Endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)' with route pattern 'Foo/fail' is valid for the request path '/foo/fail'
dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
      Request matched endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)'
trce: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[8]
      The endpoint does not specify the IRequestSizeLimitMetadata.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)'
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[102]
      Route matched with {action = "Fail", controller = "Foo"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Fail() on controller WebApplication2.Controllers.FooController (WebApplication2).
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
      Execution plan of authorization filters (in the following order): None
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
      Execution plan of resource filters (in the following order): None
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
      Execution plan of action filters (in the following order): Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter (Order: -3000), Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter (Order: -2000)
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
      Execution plan of exception filters (in the following order): None
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
      Execution plan of result filters (in the following order): Microsoft.AspNetCore.Mvc.Infrastructure.ClientErrorResultFilter (Order: -2000)
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
      Executing controller factory for controller WebApplication2.Controllers.FooController (WebApplication2)
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
      Executed controller factory for controller WebApplication2.Controllers.FooController (WebApplication2)
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
      Action Filter: Before executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
      Action Filter: After executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
      Action Filter: Before executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
      Action Filter: After executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[101]
      Executing action method WebApplication2.Controllers.FooController.Fail (WebApplication2) - Validation state: Valid
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[103]
      Executed action method WebApplication2.Controllers.FooController.Fail (WebApplication2), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 0.4942ms.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
      Action Filter: Before executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
      Action Filter: After executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
      List of registered output formatters, in the following order: Microsoft.AspNetCore.Mvc.Formatters.HttpNoContentOutputFormatter, Microsoft.AspNetCore.Mvc.Formatters.StringOutputFormatter, Microsoft.AspNetCore.Mvc.Formatters.StreamOutputFormatter, Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.DefaultOutputFormatterSelector[4]
      No information found on request to perform content negotiation.
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.DefaultOutputFormatterSelector[9]
      Attempting to select the first output formatter in the output formatters list which supports a content type from the explicitly specified content types 'application/json; charset=utf-8'.
warn: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[2]
      No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[6]
      After executing action result Microsoft.AspNetCore.Mvc.ObjectResult.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
      Result Filter: Before executing OnResultExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ClientErrorResultFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
      Result Filter: After executing OnResultExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ClientErrorResultFilter.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[105]
      Executed action WebApplication2.Controllers.FooController.Fail (WebApplication2) in 55.8371ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)'
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[9]
      Connection id "0HN4HQQ1PUQ06" completed keep alive response.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET http://localhost:5176/foo/fail - 406 0 - 154.7296ms

Expected Behavior

Expected GET http://localhost:5176/foo/fail to return 200 OK, with JSON response.
It returns 406 Not Accepted with no body.

GET http://localhost:5176/foo/pass does return 200 OK with JSON response.

Steps To Reproduce

repro-406-notaccepted-when-json-has-charset.zip

  1. Extract zip
  2. dotnet run
  3. Call GET http://localhost:5176/foo/fail, it returns 406 Not Accepted, but expected 200 OK with JSON body
  4. Call GET http://localhost:5176/foo/pass, it returns 200 OK as expected

It also does not help to specify any of these Accept headers in request:

  • Accept: application/json; charset=utf-8
  • Accept: application/json
  • Accept: application/*
  • Accept: */*

Exceptions (if any)

No response

.NET Version

8.0.301

Anything else?

Related issues

406 Not Accepted on cached response with Content-Type: application/json; charset=utf-8 · Issue #78 · ikyriak/IdempotentAPI

Versions

ASP.NET Core 8.0.6

dotnet --info
.NET SDK:
 Version:           8.0.301
 Commit:            1a0e9c0300
 Workload version:  8.0.300-manifests.011fccd5
 MSBuild version:   17.10.4+10fbfbf2e

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22631
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.301\

.NET workloads installed:
 [android]
   Installation Source: SDK 8.0.300, VS 17.9.34902.65
   Manifest Version:    34.0.95/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.android\34.0.95\WorkloadManifest.json
   Install Type:              Msi

 [ios]
   Installation Source: SDK 8.0.300, VS 17.9.34902.65
   Manifest Version:    17.2.8053/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.ios\17.2.8053\WorkloadManifest.json
   Install Type:              Msi

 [maccatalyst]
   Installation Source: SDK 8.0.300, VS 17.9.34902.65
   Manifest Version:    17.2.8053/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maccatalyst\17.2.8053\WorkloadManifest.json
   Install Type:              Msi

 [maui-windows]
   Installation Source: SDK 8.0.300, VS 17.9.34902.65
   Manifest Version:    8.0.21/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maui\8.0.21\WorkloadManifest.json
   Install Type:              Msi

 [wasi-experimental]
   Installation Source: SDK 8.0.300
   Manifest Version:    8.0.6/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.current\8.0.6\WorkloadManifest.json
   Install Type:              Msi


Host:
  Version:      8.0.6
  Architecture: x64
  Commit:       3b8b000a0e

.NET SDKs installed:
  5.0.408 [C:\Program Files\dotnet\sdk]
  6.0.321 [C:\Program Files\dotnet\sdk]
  6.0.423 [C:\Program Files\dotnet\sdk]
  7.0.120 [C:\Program Files\dotnet\sdk]
  7.0.317 [C:\Program Files\dotnet\sdk]
  8.0.106 [C:\Program Files\dotnet\sdk]
  8.0.205 [C:\Program Files\dotnet\sdk]
  8.0.301 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.19 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Activity

changed the title [-]Could not find an output formatter based on content negotiation. Accepted types were (['application/json; charset=utf-8'])[/-] [+]No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response[/+] on Jun 21, 2024
changed the title [-]No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response[/-] [+]No output formatter found when ObjectResult has content type 'application/json; charset=utf-8'[/+] on Jun 21, 2024
changed the title [-]No output formatter found when ObjectResult has content type 'application/json; charset=utf-8'[/-] [+]406 Not Accepted when returning ObjectResult with content type 'application/json; charset=utf-8'[/+] on Jun 21, 2024
added
area-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templates
on Jun 21, 2024
vanbukin

vanbukin commented on Jun 20, 2025

@vanbukin
Contributor

The issue stems from MediaTypeHeaderValue.IsSubsetOf treating parameters (like charset) as part of the comparison, even though application/json; charset=utf-8 is semantically equivalent to application/json for the purpose of JSON response formatting.

added this to the Backlog milestone on Jul 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templates

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @angularsen@martincostello@captainsafia@vanbukin

        Issue actions

          406 Not Accepted when returning ObjectResult with content type 'application/json; charset=utf-8' · Issue #56357 · dotnet/aspnetcore