Repository: microsoft/kiota (csharp)

Issue:
Breaking change: Accept header is missing in generated client
### What are you generating using Kiota, clients or plugins?

API Client/SDK

### In what context or format are you using Kiota?

Nuget tool

### Client library/SDK language

Csharp

### Describe the bug

After updating from 1.25.1 to 1.26.1, HTTP Accept headers are no longer being generated in some cases.

For example, when an endpoint defines multiple responses, where only some of them have a content type. In that case, the client should send an Accept header, to enable the server to respond with all possible statuses.

### Expected behavior

Client sends an Accept header if at least one response defines a content type.

### How to reproduce

-

### Open API description file

```json
{
  "openapi": "3.0.4",
  "paths": {
    "/api/tags/{id}/relationships/todoItems": {
      "post": {
        "summary": "Adds existing todoItems to the todoItems relationship of an individual tag.",
        "operationId": "postTagTodoItemsRelationship",
        "responses": {
          "204": {
            "description": "The todoItems were successfully added, which did not result in additional changes."
          },
          "400": {
            "description": "The request body is missing or malformed.",
            "content": {
              "application/vnd.api+json; ext=openapi": {
                "schema": {
                  "$ref": "#/components/schemas/errorResponseDocument"
                }
              }
            }
          },
          "404": {
            "description": "The tag or a related resource does not exist.",
            "content": {
              "application/vnd.api+json; ext=openapi": {
                "schema": {
                  "$ref": "#/components/schemas/errorResponseDocument"
                }
              }
            }
          },
          "409": {
            "description": "The request body contains conflicting information or another resource with the same ID already exists.",
            "content": {
              "application/vnd.api+json; ext=openapi": {
                "schema": {
                  "$ref": "#/components/schemas/errorResponseDocument"
                }
              }
            }
          },
          "422": {
            "description": "Validation of the request body failed.",
            "content": {
              "application/vnd.api+json; ext=openapi": {
                "schema": {
                  "$ref": "#/components/schemas/errorResponseDocument"
                }
              }
            }
          }
        }
      }
    },
  }
}
```

### Kiota Version

1.26.1

### Latest Kiota version known to work for scenario above?(Not required)

1.25.1

### Known Workarounds

_No response_

### Configuration

_No response_

### Debug output

_No response_

### Other information

_No response_

Pull request:
fixes #6572

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 068abba4da..a545ea63ce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Fixed a bug where path items with a trailing slash would cause collisions, missing query parameters and more.
 - Fixed a bug where path items with a trailing slash would be missing query parameters. [#6569](https://github.com/microsoft/kiota/issues/6569)
 - Fixed an issue where migration from lock to workspace would fail because of stream management. [#6515](https://github.com/microsoft/kiota/issues/6515)
+- Fixed a bug where media types from error responses would be missing from the accept header. [#6572](https://github.com/microsoft/kiota/issues/6572)
 
 ## [1.26.1] - 2025-05-15
 
diff --git a/src/Kiota.Builder/Extensions/OpenApiResponsesExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiResponsesExtensions.cs
deleted file mode 100644
index 7441db468c..0000000000
--- a/src/Kiota.Builder/Extensions/OpenApiResponsesExtensions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using Kiota.Builder.CodeDOM;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Models.Interfaces;
-
-namespace Kiota.Builder.Extensions;
-public static class OpenApiResponsesExtensions
-{
-    private static readonly HashSet<string> ignorableStatusCodesForMediaTypes = new([
-        ..Enumerable.Range(400, 599).Select(static x => x.ToString(CultureInfo.InvariantCulture)),
-        CodeMethod.ErrorMappingClientRange,
-        CodeMethod.ErrorMappingServerRange,
-        "default"]);
-
-    public static IEnumerable<KeyValuePair<string, IOpenApiResponse>> WhereValidForMediaTypeSelection(this OpenApiResponses responses)
-        => responses.Where(static x => !ignorableStatusCodesForMediaTypes.Contains(x.Key) && x.Value.Content is not null);
-}
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index 04a7298e72..6225ac5b4e 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -1264,6 +1264,7 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten
     private static readonly HashSet<string> noContentStatusCodes = new(redirectStatusCodes, StringComparer.OrdinalIgnoreCase) { "201", "202", "204", "205", "304" };
     private static readonly HashSet<string> errorStatusCodes = new(Enumerable.Range(400, 599).Select(static x => x.ToString(CultureInfo.InvariantCulture))
                                                                                  .Concat([CodeMethod.ErrorMappingClientRange, CodeMethod.ErrorMappingServerRange]), StringComparer.OrdinalIgnoreCase);
+    private static readonly HashSet<string> errorStatusCodesWithDefault = new(errorStatusCodes, StringComparer.OrdinalIgnoreCase) { DefaultResponseIndicator };
     private void AddErrorMappingsForExecutorMethod(OpenApiUrlTreeNode currentNode, OpenApiOperation operation, CodeMethod executorMethod)
     {
         if (operation.Responses is null) return;
@@ -1474,15 +1475,17 @@ private void CreateOperationMethods(OpenApiUrlTreeNode currentNode, NetHttpMetho
             {
                 (_, true) => [],
                 (null, _) => operation.Responses!
-                                .WhereValidForMediaTypeSelection()
-                                .SelectMany(static x => x.Value.Content!)
-                                .Select(static x => x.Key) //get the successful non structured media types first, with a default 1 priority
-                                .Union(config.StructuredMimeTypes.GetAcceptedTypes(
-                                                            operation.Responses!
-                                                            .WhereValidForMediaTypeSelection()
-                                                            .SelectMany(static x => x.Value.Content!) // we can safely ignore unstructured ones as they won't be used in error mappings anyway and the body won't be read
-                                                            .Select(static x => x.Key)))
-                        .Distinct(StringComparer.OrdinalIgnoreCase),
+                            .Where(static x => !errorStatusCodesWithDefault.Contains(x.Key) && x.Value.Content is not null)
+                            .SelectMany(static x => x.Value.Content!)
+                            .Select(static x => x.Key)
+                            .Select(static x => x.Split(';', StringSplitOptions.RemoveEmptyEntries)[0]) //get the successful non structured media types first, with a default 1 priority
+                            .Union(config.StructuredMimeTypes
+                                        .GetAcceptedTypes(
+                                            operation.Responses!
+                                                .Where(static x => errorStatusCodesWithDefault.Contains(x.Key) && x.Value.Content is not null) // get any structured error ones, with the priority from the configuration
+                                                .SelectMany(static x => x.Value.Content!) // we can safely ignore unstructured ones as they won't be used in error mappings anyway and the body won't be read
+                                                .Select(static x => x.Key)))
+                            .Distinct(StringComparer.OrdinalIgnoreCase),
                 (_, false) => config.StructuredMimeTypes.GetAcceptedTypes(operation.Responses!.Values.Where(static x => x.Content is not null).SelectMany(static x => x.Content!).Where(x => schemaReferenceComparer.Equals(schema, x.Value.Schema)).Select(static x => x.Key)),
             };
             generatorMethod.AddAcceptedResponsesTypes(mediaTypes);


Test patch:
diff --git a/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs b/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs
index 4a3ff6f07e..6c31cc4019 100644
--- a/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs
+++ b/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs
@@ -329,6 +329,86 @@ public void GeneratesTheRightAcceptHeaderBasedOnContentAndStatus(string contentM
     }
     [Theory]
     [InlineData("application/json, text/plain", "application/json", "application/json", "text/plain")]
+    [InlineData("application/json, text/plain, application/yaml", "application/json;q=0.8,application/yaml", "application/yaml,application/json;q=0.8", "text/plain")]
+    [InlineData("*/*", "application/json;q=0.8", "", "application/json;q=0.8")]
+    [InlineData("application/json, */*", "application/json;q=0.8", "application/json;q=0.8", "*/*")]
+    [InlineData("application/png, application/jpg", "application/json;q=0.8", "", "application/json;q=0.8")]
+    public void IncludeErrorsMediaTypeInAcceptHeader(string contentMediaTypes, string structuredMimeTypes, string expectedAcceptHeader, string unexpectedMimeTypes)
+    {
+        var document = new OpenApiDocument
+        {
+            Paths = new OpenApiPaths
+            {
+                ["answer"] = new OpenApiPathItem
+                {
+                    Operations = new()
+                    {
+                        [NetHttpMethod.Get] = new OpenApiOperation
+                        {
+                            Responses = new OpenApiResponses
+                            {
+                                ["204"] = new OpenApiResponse(),
+                                ["403"] = new OpenApiResponse
+                                {
+                                    Content = contentMediaTypes.Split(',').Select(x => new
+                                    {
+                                        Key = x.Trim(),
+                                        value = new OpenApiMediaType
+                                        {
+                                            Schema = new OpenApiSchemaReference("myobject"),
+                                        }
+                                    }).ToDictionary(x => x.Key, x => x.value)
+                                },
+                            }
+                        }
+                    }
+                }
+            },
+            Components = new()
+            {
+                Schemas = new Dictionary<string, IOpenApiSchema> {
+                    {
+                        "myobject", new OpenApiSchema {
+                            Type = JsonSchemaType.Object,
+                            Properties = new Dictionary<string, IOpenApiSchema> {
+                                {
+                                    "id", new OpenApiSchema {
+                                        Type = JsonSchemaType.String,
+                                    }
+                                }
+                            },
+                        }
+                    }
+                }
+            }
+        };
+        document.RegisterComponents();
+        document.SetReferenceHostDocument();
+        var mockLogger = new Mock<ILogger<KiotaBuilder>>();
+        var builder = new KiotaBuilder(
+            mockLogger.Object,
+            new GenerationConfiguration
+            {
+                ClientClassName = "TestClient",
+                ClientNamespaceName = "TestSdk",
+                ApiRootUrl = "https://localhost",
+                StructuredMimeTypes = new(structuredMimeTypes.Split(',').Select(x => x.Trim()))
+            }, _httpClient);
+        var node = builder.CreateUriSpace(document);
+        var codeModel = builder.CreateSourceModel(node);
+        var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer");
+        Assert.NotNull(rbNS);
+        var rbClass = rbNS.Classes.FirstOrDefault(static x => x.IsOfKind(CodeClassKind.RequestBuilder));
+        Assert.NotNull(rbClass);
+        var generator = rbClass.Methods.FirstOrDefault(static x => x.IsOfKind(CodeMethodKind.RequestGenerator));
+        Assert.NotNull(generator);
+        foreach (var header in expectedAcceptHeader.Split(',', StringSplitOptions.RemoveEmptyEntries))
+            Assert.Contains(header.Trim(), generator.AcceptedResponseTypes);
+        foreach (var header in unexpectedMimeTypes.Split(','))
+            Assert.DoesNotContain(header.Trim(), generator.AcceptedResponseTypes);
+    }
+    [Theory]
+    [InlineData("application/json, text/plain", "application/json", "application/json", "text/plain")]
     [InlineData("application/json, text/plain, application/yaml", "application/json;q=0.8,application/yaml", "application/yaml", "text/plain")]
     [InlineData("*/*", "application/json;q=0.8", "", "application/json")]
     [InlineData("application/json, */*", "application/json;q=0.8", "application/json", "*/*")]
diff --git a/tests/Kiota.Builder.Tests/Extensions/OpenApiResponsesExtensionsTests.cs b/tests/Kiota.Builder.Tests/Extensions/OpenApiResponsesExtensionsTests.cs
deleted file mode 100644
index aacc63af86..0000000000
--- a/tests/Kiota.Builder.Tests/Extensions/OpenApiResponsesExtensionsTests.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-﻿using System.Collections.Generic;
-using System.Linq;
-using Kiota.Builder.Extensions;
-using Microsoft.OpenApi.Models;
-using Xunit;
-
-namespace Kiota.Builder.Tests.Extensions;
-public class OpenApiResponsesExtensionsTests
-{
-    [Fact]
-    public void WhereValidForMediaTypeSelectionReturnsAllIfNothingToFilterOut()
-    {
-        var sut = CreateWithStatusCodes(["100", "200", "201", "202", "204", "304", "307"]);
-        var result = sut.WhereValidForMediaTypeSelection().ToList();
-        Assert.Equal(7, result.Count);
-        Assert.Equal(["100", "200", "201", "202", "204", "304", "307"], result.Select(r => r.Key));
-    }
-
-    [Fact]
-    public void WhereValidForMediaTypeSelectionRemoves400RangeEntries()
-    {
-        var sut = CreateWithStatusCodes(["200", "304", "400", "469", "499", "4XX"]);
-        var result = sut.WhereValidForMediaTypeSelection().ToList();
-        Assert.Equal(2, result.Count);
-        Assert.Equal(["200", "304"], result.Select(r => r.Key));
-    }
-
-    [Fact]
-    public void WhereValidForMediaTypeSelectionRemoves500RangeEntries()
-    {
-        var sut = CreateWithStatusCodes(["200", "304", "500", "569", "599", "5XX"]);
-        var result = sut.WhereValidForMediaTypeSelection().ToList();
-        Assert.Equal(2, result.Count);
-        Assert.Equal(["200", "304"], result.Select(r => r.Key));
-    }
-
-    [Fact]
-    public void WhereValidForMediaTypeSelectionRemovesDefaultEntry()
-    {
-        var sut = CreateWithStatusCodes(["200", "304", "default"]);
-        var result = sut.WhereValidForMediaTypeSelection().ToList();
-        Assert.Equal(2, result.Count);
-        Assert.Equal(["200", "304"], result.Select(r => r.Key));
-    }
-
-    private OpenApiResponses CreateWithStatusCodes(string[] statusCodes)
-    {
-        var responses = new OpenApiResponses();
-        foreach (var sc in statusCodes)
-        {
-            responses.Add(sc, new OpenApiResponse
-            {
-                Content = new Dictionary<string, OpenApiMediaType>
-                {
-                    ["application/json"] = new OpenApiMediaType()
-                }
-            });
-        }
-        return responses;
-    }
-}