Skip to content

application/problem+json content type is not set for ProblemDetails #2982

Closed
@T-bond

Description

@T-bond

Thank you for implementing #2963, but it seems to be it is not working yet.

Describe the bug
application/problem+json content type should be generated for endpoints, where the content type is not explicitly overridden,
but it still generates the default produces media type.

To Reproduce
Has the same setup as described in the referenced ticket, but with Springdoc 2.8.7 (or preferably 2.8.8)
Spring configuration:

spring.mvc.problemdetails.enabled=true
springdoc.default-produces-media-type=application/json
...
import org.springframework.http.ProblemDetail

@ControllerAdvice
class GlobalExceptionHandler {
    @ExceptionHandler
    @ApiResponse(responseCode = "404", description = "Description for API users...")
    fun myCustomError(exception: MyCustomException) = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST)
}

(I replaced ResponseStatus with ApiResponse just to provide a description to the users of the API, but from the code it seems like (from commit 0cd571a), the ApiResponse annotation also required for the automated ProblemDetail content type resolver to work)

  • Investigate that the generated content type is still the default media type, not the application/problem+json.
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'

Expected behavior

  • The RFC defined problem detail content type is generated in the OpenAPI documentation.

Screenshots
Seems like the check for replacing the content type only checks for the configuration default content type */*, instead of
the springdoc.default-produces-media-type configured one.
Image

Additional context

Possible solution:
I have not tested it, but if I get this right, instead of using MediaType.ALL_VALUE in line:

io.swagger.v3.oas.models.media.MediaType mediaType = content.get(MediaType.ALL_VALUE);
and
it should use: springDocConfigProperties.getDefaultProducesMediaType() .

Output of `./gradlew -q :app:dependencyInsight --dependency org.springdoc`:

org.springdoc:springdoc-openapi-starter-common:2.8.8
  Variant compile:
    | Attribute Name                     | Provided | Requested    |
    |------------------------------------|----------|--------------|
    | org.gradle.status                  | release  |              |
    | org.gradle.category                | library  | library      |
    | org.gradle.libraryelements         | jar      | classes      |
    | org.gradle.usage                   | java-api | java-api     |
    | org.gradle.dependency.bundling     |          | external     |
    | org.gradle.jvm.environment         |          | standard-jvm |
    | org.gradle.jvm.version             |          | 21           |
    | org.jetbrains.kotlin.platform.type |          | jvm          |

org.springdoc:springdoc-openapi-starter-common:2.8.8
\--- org.springdoc:springdoc-openapi-starter-webmvc-api:2.8.8
     \--- org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8
          \--- compileClasspath

org.springdoc:springdoc-openapi-starter-webmvc-api:2.8.8
  Variant compile:
    | Attribute Name                     | Provided | Requested    |
    |------------------------------------|----------|--------------|
    | org.gradle.status                  | release  |              |
    | org.gradle.category                | library  | library      |
    | org.gradle.libraryelements         | jar      | classes      |
    | org.gradle.usage                   | java-api | java-api     |
    | org.gradle.dependency.bundling     |          | external     |
    | org.gradle.jvm.environment         |          | standard-jvm |
    | org.gradle.jvm.version             |          | 21           |
    | org.jetbrains.kotlin.platform.type |          | jvm          |

org.springdoc:springdoc-openapi-starter-webmvc-api:2.8.8
\--- org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8
     \--- compileClasspath

org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8 (selected by rule)
  Variant compile:
    | Attribute Name                     | Provided | Requested    |
    |------------------------------------|----------|--------------|
    | org.gradle.status                  | release  |              |
    | org.gradle.category                | library  | library      |
    | org.gradle.libraryelements         | jar      | classes      |
    | org.gradle.usage                   | java-api | java-api     |
    | org.gradle.dependency.bundling     |          | external     |
    | org.gradle.jvm.environment         |          | standard-jvm |
    | org.gradle.jvm.version             |          | 21           |
    | org.jetbrains.kotlin.platform.type |          | jvm          |

org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8
\--- compileClasspath

A web-based, searchable dependency report is available by adding the --scan option.

Activity

marceloverdijk

marceloverdijk commented on May 8, 2025

@marceloverdijk

I came here via #2963 as I'm facing the same issue.

I also have springdoc.default-produces-media-type=application/json, but I want to use application/problem+json for error responses (400, 401, etc).

Ideally springdoc should be able to use the produces from the ExceptionHandler like:

@ExceptionHandler(value = [Throwable::class], produces = [APPLICATION_PROBLEM_JSON_VALUE])

but that seems not to be supported at the moment.

Note I got it working by adding the @ApiResponse explicitly, but it's a bit tedious and contains a lot of duplication to that for all exception handlers.
Also note I'm using a custom ProblemDetailDto which contains @Schema descriptions for better documentation..

@RestControllerAdvice
class GlobalExceptionHandler : ResponseEntityExceptionHandler() {
    companion object {
        private val BLANK_TYPE: URI = URI.create("about:blank")
    }

    @ExceptionHandler(value = [Throwable::class], produces = [APPLICATION_PROBLEM_JSON_VALUE])
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    @ApiResponse(
        responseCode = "500",
        content = [
            Content(
                mediaType = APPLICATION_PROBLEM_JSON_VALUE,
                schema = Schema(implementation = ProblemDetailDto::class),
            ),
        ],
    )
    fun error(e: Throwable): ResponseEntity<ProblemDetailDto> {
        val status = HttpStatus.INTERNAL_SERVER_ERROR
        val problemDetail =
            ProblemDetailDto(
                type = BLANK_TYPE,
                status = status.value(),
                title = status.reasonPhrase,
            )
        return ResponseEntity
            .status(status)
            .contentType(APPLICATION_PROBLEM_JSON)
            .body(problemDetail)
    }
}
Image
MarcoMartins86

MarcoMartins86 commented on May 13, 2025

@MarcoMartins86

Also facing this issue, +1 for reading the produces from ExceptionHandler.

added a commit that references this issue on Jun 10, 2025
ceb4a10
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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @marceloverdijk@T-bond@bnasslahsen@MarcoMartins86

        Issue actions

          `application/problem+json` content type is not set for ProblemDetails · Issue #2982 · springdoc/springdoc-openapi