{"id":23789794,"url":"https://github.com/officiallysingh/spring-boot-problem-handler","last_synced_at":"2026-01-20T13:00:44.485Z","repository":{"id":186493894,"uuid":"654897642","full_name":"officiallysingh/spring-boot-problem-handler","owner":"officiallysingh","description":"Common exception handler for Spring boot web applications","archived":false,"fork":false,"pushed_at":"2026-01-19T12:52:24.000Z","size":639,"stargazers_count":38,"open_issues_count":2,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-19T19:34:52.782Z","etag":null,"topics":["controller-advice","exception-handling","exceptions","problemdetails","spring-boot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/officiallysingh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-06-17T09:12:36.000Z","updated_at":"2026-01-19T12:52:29.000Z","dependencies_parsed_at":"2023-09-24T08:05:23.300Z","dependency_job_id":"5e28806e-d815-4ab5-ae37-4e509f447b91","html_url":"https://github.com/officiallysingh/spring-boot-problem-handler","commit_stats":null,"previous_names":["officiallysingh/spring-boot-problem-handler"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/officiallysingh/spring-boot-problem-handler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/officiallysingh%2Fspring-boot-problem-handler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/officiallysingh%2Fspring-boot-problem-handler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/officiallysingh%2Fspring-boot-problem-handler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/officiallysingh%2Fspring-boot-problem-handler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/officiallysingh","download_url":"https://codeload.github.com/officiallysingh/spring-boot-problem-handler/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/officiallysingh%2Fspring-boot-problem-handler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28603402,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T12:01:53.233Z","status":"ssl_error","status_checked_at":"2026-01-20T12:01:46.545Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["controller-advice","exception-handling","exceptions","problemdetails","spring-boot"],"created_at":"2025-01-01T17:16:43.107Z","updated_at":"2026-01-20T13:00:44.475Z","avatar_url":"https://github.com/officiallysingh.png","language":"Java","funding_links":[],"categories":["REST错误处理"],"sub_categories":[],"readme":"# Ultimate guide for Exception handling in Spring Boot applications\n\n**A Generic library for handling exceptions in Spring Boot applications**, \nimplementing specification [**`Problem Details (RFC7807) for HTTP APIs`**](https://datatracker.ietf.org/doc/html/rfc7807).\nRequires Java 17+, Spring boot 4+ and Jakarta EE 10. Use version `1.9.3` for Spring boot 3.x\n\n![Exception Handling](https://miro.medium.com/v2/resize:fit:1400/format:webp/1*0s2E6-iNFqr_xptwrmJTdg.jpeg)\n\n## Table of Contents\n1. [Introduction](#introduction)\n2. [Installation](#installation)\n3. [Features offered](https://github.com/officiallysingh/spring-boot-problem-handler#features)\n4. [Controller Advices bundled with library](#controller-advices)\n   - [General advices for web applications](#general-advices-recommended-for-all-spring-rest-services)\n   - [DAO advices for relational databases and MongoDB](#dao-advices) \n   - [Security advices for common security exceptions](#security-advices)\n   - [OpenAPI validation advice for API specification validations](#openapi-validation-advice)\n5. [Spring Configurations](#configurations)\n6. [Problem Properties to customize the behaviour](#problem-properties)\n7. [Error Key, the central concept behind error attribute's externalization](#error-key)\n8. [Error response characteristics](#error-response)\n9. [Message resolvers to externalize error response in `properties` files](#message-resolvers)\n10. [Message internationalization or i18n](#message-internationalization)\n11. [Tracing](#tracing)\n12. [Creating and throwing exceptions in your applications](#creating-and-throwing-exceptions)\n13. [Stack trace embedded in error response](#stack-traces)\n14. [Cause chains embedded in error response](#cause-chains)\n15. [Customizations of default behaviour](#customizations)\n    - [Customize error response](#customize-error-response)\n    - [Customize or Override advices](#customize-or-override-advices)\n16. [Define new advices](#define-new-advices)\n17. [Testing support](#testing-support)\n18. [Example error responses in different scenarios](#example-error-responses)\n\n## Introduction\n\nException handling is a cross-cutting concern, should be kept separate from business logic and applied declaratively. \n\nA common practice is to create some custom exception classes like some ServiceException and errors code enums, \nwherein each instance of error code enum represents an error scenario.\nAn exception class could be either checked or unchecked, but handling of exception is no different. \nFor almost all error scenarios unchecked exception can serve the purpose really well, \nsaving developers from explicitly writing `try` `catch` blocks and `throws` clauses. Though not recommended but \n limited, checked exceptions can be created and thrown from methods where calling programs can take some recovery measures.\n\nStandard way of handling exceptions in Spring is `@ControllerAdvice` using AOP, \nfollowing the same principles **spring-boot-problem-handler** makes available everything related to exception handling \nfor both **Spring Web** (Servlet) and **Spring Webflux** (Reactive) Rest applications, \nso there is no need to define any custom exceptions or custom `ControllerAdvice` advices into consumer application, \nall can be done with zero custom code but by specifying error details in `properties` file.\n\n## Installation\n\n\u003e **Current version: 1.10.4** Refer to [Release notes](https://github.com/officiallysingh/spring-boot-problem-handler/releases) while upgrading\n\nAdd the `spring-boot-problem-handler` jar to application dependencies. That is all it takes to get a default working \nexception handling mechanism in a Spring boot application.\n\n\u003e [!IMPORTANT]\nJar is built on java 17. For earlier versions of java, please build from source code.\n\nMaven\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.officiallysingh\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-problem-handler\u003c/artifactId\u003e\n    \u003cversion\u003e1.10.4\u003c/version\u003e\n\u003c/dependency\u003e\n```\nGradle\n```groovy\nimplementation 'io.github.officiallysingh:spring-boot-problem-handler:1.10.4'\n```\n\nIt does all hard part, A lot of advices are out of box available that are autoconfigured as `ControllerAdvice`s \ndepending on the jars in classpath of consumer application. \n**Even for exceptions for which no advices are defined**, respective error response can be specified by \nmessages in `properties` file, elaborated in [*Usage*](https://github.com/officiallysingh/spring-boot-problem-handler#usage) section.\nNew custom advice could be required only in cases where it is required to take some data from exception instance \nto dynamically derive [*Error key*](https://github.com/officiallysingh/spring-boot-problem-handler#error-key) \nor to use this data to resolve any placeholders in an error message. In such cases consumer application can define \ntheir own custom `ControllerAdvice`'s,\nAny existing advice can be referred to weave the custom advice into the framework.\n\n\u003e A default set of `ControllerAdvice`s are always configured irrespective of the fact that whether \nthe application is Spring Web or Spring Webflux. However, few advices are conditional \nsuch as for Handling Security, OpenAPI and Dao related exceptions, which are elaborated in their respective sections.\n\n## Features\n\n* A lot of inbuilt `ControllerAdvice`'s out of box available to handle most common exceptions.\n* Extendable to add more advices or override existing advices in consumer applications, weaving them into an aligned framework for exception handling.\n* Customizable Error response structure.\n* Provides a mechanism to specify error response for any kind of exception without defining any `ControllerAdvice`.\n* Works with both Spring Web and Spring Webflux applications.\n* Customizable to override the default attributes in error response by overriding the same in `properties` file.\n* The autoconfigured advices can be disabled or overridden or extended as per needs.\n* Micrometer tracing support.\n\n## Controller Advices\n\n#### General advices recommended for all Spring Rest services\n\nThese advices are autoconfigured as either bean of type [**`ProblemHandlingWeb`**](src/main/java/com/ksoot/problem/spring/advice/web/ProblemHandlingWeb.java) \nor [**`ProblemHandlingWebflux`**](src/main/java/com/ksoot/problem/spring/advice/webflux/ProblemHandlingWebflux.java) depending on whether application is type **Spring Web** or **Spring Webflux** respectively.\n\n| General Advice Traits                                                                                                                                         | Produces                                                    | Error Key                                                           |\n|---------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------|---------------------------------------------------------------------|\n| [**`ApplicationAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/application/ApplicationAdviceTraits.java)                                       |                                                             |                                                                     |\n| `├──`[`ApplicationProblemAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/application/ApplicationProblemAdviceTrait.java)                          | *depends*                                                   | Provided by application while throwing exception                    |\n| `├──`[`ApplicationExceptionAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/application/ApplicationExceptionAdviceTrait.java)                      | *depends*                                                   | Provided by application while throwing exception                    |\n| `└──`[ `ApplicationMultiProblemAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/application/ApplicationMultiProblemAdviceTrait.java)               | *depends*                                                   | Provided by application while throwing exception                    |\n| [**`GeneralAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/general/GeneralAdviceTraits.java)                                                   |                                                             |                                                                     |\n| `├──`[`ProblemAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/general/ProblemAdviceTrait.java)                                                    | [`500 Internal Server Error`](https://httpstatus.es/500)    | internal.server.error                                               |\n| `├──`[`ThrowableAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/general/ThrowableAdviceTrait.java)                                                | [`500 Internal Server Error`](https://httpstatus.es/500)    | internal.server.error                                               |\n| `└──`[ `UnsupportedOperationAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/general/UnsupportedOperationAdviceTrait.java)                         | [`501 Not Implemented`](https://httpstatus.es/501)          | java.lang.UnsupportedOperationException                             |\n| [**`HttpAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/http/HttpAdviceTraits.java)                                                            |                                                             |                                                                     |\n| `├──`[`HttpMediaTypeNotAcceptableAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/http/HttpMediaTypeNotAcceptableAdviceTrait.java)                 | [`415 Unsupported Media Type`](https://httpstatus.es/415)   | media.type.not.acceptable                                           |\n| `├──`[`HttpMediaTypeNotSupportedExceptionAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/http/HttpMediaTypeNotSupportedExceptionAdviceTrait.java) | [`415 Unsupported Media Type`](https://httpstatus.es/415)   | media.type.not.supported                                            |\n| `├──`[`UnsupportedMediaTypeStatusAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/http/UnsupportedMediaTypeStatusAdviceTrait.java)                 | [`415 Unsupported Media Type`](https://httpstatus.es/415)   | media.type.not.supported                                            |\n| `├──`[`HttpRequestMethodNotSupportedAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/http/http/HttpRequestMethodNotSupportedAdviceTrait.java)      | [`405 Method Not Allowed`](https://httpstatus.es/405)       | request.method.not.supported                                        |\n| `├──`[`MethodNotAllowedAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/http/MethodNotAllowedAdviceTrait.java)                                     | [`405 Method Not Allowed`](https://httpstatus.es/405)       | method.not.allowed                                                  |\n| `├──`[`NotAcceptableStatusAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/http/NotAcceptableStatusAdviceTrait.java)                               | [`406 Not Acceptable`](https://httpstatus.es/406)           | org.springframework.web.server.NotAcceptableStatusException         |\n| `└──`[`ResponseStatusAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/http/ResponseStatusAdviceTrait.java)                                         | *depends*                                                   |                                                                     |\n| [**`IOAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/io/IOAdviceTraits.java)                                                                  |                                                             |                                                                     |\n| `├──`[`MessageNotReadableAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/io/MessageNotReadableAdviceTrait.java)                                   | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `├──`[`MultipartAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/io/MultipartAdviceTrait.java)                                                     | [`400 Bad Request`](https://httpstatus.es/400)              | org.springframework.web.multipart.MultipartException                |\n| `└──`[`MultipartAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/io/MaxUploadSizeExceededExceptionAdviceTrait.java)                                | [`400 Bad Request`](https://httpstatus.es/400)              | org.springframework.web.multipart.MaxUploadSizeExceededException    |\n| [**`RoutingAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/routing/RoutingAdviceTraits.java)                                                   |                                                             |                                                                     |\n| `├──`[`MissingRequestHeaderAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/routing/MissingRequestHeaderAdviceTrait.java)                          | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `├──`[`MissingServletRequestParameterAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/routing/MissingServletRequestParameterAdviceTrait.java)      | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `├──`[`MissingServletRequestPartAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/routing/MissingServletRequestPartAdviceTrait.java)                | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `├──`[`NoHandlerFoundAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/routing/NoHandlerFoundAdviceTrait.java)                                      | [`404 Not Found`](https://httpstatus.es/404)                | no.handler.found                                                    |\n| `└──`[`ServletRequestBindingAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/routing/ServletRequestBindingAdviceTrait.java)                        | [`400 Bad Request`](https://httpstatus.es/400)              | org.springframework.web.bind.ServletRequestBindingException         |\n| [**`ValidationAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/validation/ValidationAdviceTraits.java)                                          |                                                             |                                                                     |\n| `├──`[`ConstraintViolationAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/validation/ConstraintViolationAdviceTrait.java)                         | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `├──`[`BindAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/validation/BindAdviceTrait.java)                                                       | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `├──`[`MethodArgumentNotValidAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/validation/MethodArgumentNotValidAdviceTrait.java)                   | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `├──`[`MethodArgumentTypeMismatchAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/validation/MethodArgumentTypeMismatchAdviceTrait.java)           | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| `└──`[`TypeMismatchAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/validation/TypeMismatchAdviceTrait.java)                                       | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n| [`WebExchangeBindAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/webflux/WebExchangeBindAdviceTrait.java)                                         | [`400 Bad Request`](https://httpstatus.es/400)              | *Derived* from exception                                            |\n\n\n**Composite advice traits**\n\n| Spring Web Advice Traits                                                                                                  | Spring Webflux Advice Traits                                                                                   |\n|---------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|\n| [**`ProblemHandlingWeb`**](src/main/java/com/ksoot/problem/spring/advice/web/ProblemHandlingWeb.java)                     | [**`ProblemHandlingWebflux`**](src/main/java/com/ksoot/problem/spring/advice/webflux/ProblemHandlingWebflux.java)   |\n| `├──`[`GeneralAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/general/GeneralAdviceTraits.java)              | `├──`[`GeneralAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/general/GeneralAdviceTraits.java)              |\n| `├──`[`HttpAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/http/HttpAdviceTraits.java)                       | `├──`[`HttpAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/http/HttpAdviceTraits.java)                       |\n| `├──`[`IOAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/io/IOAdviceTraits.java)                             | `├──`[`IOAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/io/IOAdviceTraits.java)                             |\n| `├──`[ `RoutingAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/routing/RoutingAdviceTraits.java)             | `├──`[`WebExchangeBindAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/webflux/WebExchangeBindAdviceTrait.java) |\n| `├──`[ `ValidationAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/validation/ValidationAdviceTraits.java)    | `├──`[`ValidationAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/validation/ValidationAdviceTraits.java)     |\n| `└──`[ `ApplicationAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/application/ApplicationAdviceTraits.java) | `└──`[`ApplicationAdviceTraits`](src/main/java/com/ksoot/problem/spring/advice/application/ApplicationAdviceTraits.java)  |\n\n\n#### DAO advices\n\n| DAO Advice Traits                                                                                                                        | Produces                                                  | Error Key                                              |\n|------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------|--------------------------------------------------------|\n| [**`DaoAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/dao/DaoAdviceTraits.java)                                          |                                                           |                                                        | \n| `├──`[**`DataIntegrityViolationAdviceTrait`**](src/main/java/com/ksoot/problem/spring/advice/dao/DataIntegrityViolationAdviceTrait.java) | [`500 Internal Server Error`](https://httpstatus.es/500)  | data.integrity.violation.\\\u003cFailed DB constraint name\\\u003e |\n| `└──`[**`DuplicateKeyExceptionAdviceTrait`**](src/main/java/com/ksoot/problem/spring/advice/dao/DuplicateKeyExceptionAdviceTrait.java)   | [`500 Internal Server Error`](https://httpstatus.es/500)  | data.integrity.violation.\\\u003cFailed DB constraint name\\\u003e |\n\nThese advices are autoconfigured as [**`WebDaoExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/WebDaoExceptionHandler.java) \nor [**`WebFluxDaoExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/webflux/WebFluxDaoExceptionHandler.java) \nfor Spring Web and Spring Webflux respectively, if following conditions are true\n* `problem.dao-advice-enabled` is not set to `false`. Its default value is `true`\n* If using relation databases then `spring-data-jpa` jar is detected in classpath and either `spring.datasource.url` or `spring.r2dbc.url` is configured\n* If using MongoDB then `spring-data-mongodb` jar is detected in classpath and `spring.data.mongodb.uri` is configured\n\n\u003e [!NOTE]\n\u003e Database type must be specified in `application.properties` in case application is using some relational database, \nit is used to autoconfigure [**`ConstraintNameResolver`**](src/main/java/com/ksoot/problem/spring/advice/dao/ConstraintNameResolver.java) to extract database constraint name from exception message to derive [*Error key*](https://github.com/officiallysingh/spring-boot-problem-handler#error-key) \nwhen database constraint violation exceptions are thrown.\n\n#### Security advices\n\n| Security Advice Traits                                                                                                                                | Produces                                        | Error Key              |\n|-------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|------------------------|\n| [**`SecurityAdviceTraits`**](src/main/java/com/ksoot/problem/spring/advice/security/SecurityAdviceTraits.java)                                        |                                                 |                        |\n| `├──`[**`AuthenticationAdviceTrait`**](src/main/java/com/ksoot/problem/spring/advice/security/AuthenticationAdviceTrait.java)                         | [`401 Unauthorized`](https://httpstatus.es/401) | security.unauthorized  |\n| `├──`[**`InsufficientAuthenticationAdviceTrait`**](src/main/java/com/ksoot/problem/spring/advice/security/InsufficientAuthenticationAdviceTrait.java) | [`401 Unauthorized`](https://httpstatus.es/401) | security.unauthorized  |\n| `└──`[**`AccessDeniedAdviceTrait`**](src/main/java/com/ksoot/problem/spring/advice/security/AccessDeniedAdviceTrait.java)                             | [`403 Forbidden`](https://httpstatus.es/403)    | security.access.denied |\n\nThese advices are autoconfigured as a bean `SecurityExceptionHandler` if following conditions are true\n* `spring-security-config` jar is detected in classpath\n* `problem.security-advice-enabled` is not set to `false`. Its default value is `true`\n\n\u003e **For Spring Web applications** \n[**`ProblemAuthenticationEntryPoint`**](src/main/java/com/ksoot/problem/spring/advice/security/ProblemAuthenticationEntryPoint.java)\nand [**`ProblemAccessDeniedHandler`**](src/main/java/com/ksoot/problem/spring/advice/security/ProblemAccessDeniedHandler.java) \nare autoconfigured as `authenticationEntryPoint` and `accessDeniedHandler` beans respectively. \n\nBut to make it work, the following needs to be done in the application's Spring Security configuration. \nRefer to example [**`WebSecurityConfiguration`**](https://github.com/officiallysingh/problem-handler-web-demo/blob/main/src/main/java/com/ksoot/problem/demo/config/WebSecurityConfiguration.java)\n```java\n@Autowired\nprivate AuthenticationEntryPoint authenticationEntryPoint;\n\n@Autowired\nprivate AccessDeniedHandler accessDeniedHandler;\n\n@Bean\npublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n    // Your security configurations\n    http.csrf(AbstractHttpConfigurer::disable)\n            .authorizeHttpRequests((requests) -\u003e requests\n                .requestMatchers(\"/swagger-resources/**\", \"/swagger-ui/**\", \"/swagger-ui.*\", \"/v3/api-docs\", \"/v3/api-docs/**\", \"/webjars/**\")\n                .permitAll()\n//                .requestMatchers(\n//                        // Add\n//                )\n                .permitAll()\n                .anyRequest()\n                .authenticated()\n            );\n\n    if (this.authenticationEntryPoint != null) {\n      http.exceptionHandling(\n              exceptionHandling -\u003e\n                      exceptionHandling.authenticationEntryPoint(this.authenticationEntryPoint));\n    }\n    if (this.accessDeniedHandler != null) {\n      http.exceptionHandling(\n              exceptionHandling -\u003e exceptionHandling.accessDeniedHandler(this.accessDeniedHandler));\n    }\n    \n    return http.build();\n}\n```\n\n\u003e **For Spring Webflux applications** \n[**`ProblemServerAuthenticationEntryPoint`**](src/main/java/com/ksoot/problem/spring/advice/security/ProblemServerAuthenticationEntryPoint.java)\nand [**`ProblemServerAccessDeniedHandler`**](src/main/java/com/ksoot/problem/spring/advice/security/ProblemServerAccessDeniedHandler.java)\nare autoconfigured as `authenticationEntryPoint` and `accessDeniedHandler` beans respectively.\n\nBut to make it work, the following needs to be done in application Spring Security configuration. \nRefer to example [**`WebFluxSecurityConfiguration`**](https://github.com/officiallysingh/problem-handler-webflux-demo/blob/main/src/main/java/com/ksoot/problem/demo/config/WebFluxSecurityConfiguration.java)\n```java\n@Autowired\nprivate ServerAuthenticationEntryPoint authenticationEntryPoint;\n\n@Autowired\nprivate ServerAccessDeniedHandler accessDeniedHandler;\n\n@Bean\nSecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {\n    // Your security configurations\n    http.csrf(ServerHttpSecurity.CsrfSpec::disable)\n            .authorizeExchange((exchanges) -\u003e exchanges\n                .pathMatchers(\"/swagger-resources/**\", \"/swagger-ui/**\", \"/swagger-ui.*\", \"/v3/api-docs\", \"/v3/api-docs/**\", \"/webjars/**\")\n                .permitAll()\n//                .pathMatchers(\n//                        // Add\n//                )\n                .permitAll()\n                .anyExchange().authenticated()\n            );\n  \n    if (this.authenticationEntryPoint != null) {\n      http.exceptionHandling(\n              exceptionHandling -\u003e\n                      exceptionHandling.authenticationEntryPoint(this.authenticationEntryPoint));\n    }\n    if (this.accessDeniedHandler != null) {\n      http.exceptionHandling(\n              exceptionHandling -\u003e exceptionHandling.accessDeniedHandler(this.accessDeniedHandler));\n    }\n  \n    return http.build();\n}\n```\n\n#### OpenAPI validation advice\n\n| OpenAPI Validation Advice Traits                                                                                                   | Produces                                        | Error Key                  |\n|------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|----------------------------|\n| [**`OpenApiValidationAdviceTrait`**](src/main/java/com/ksoot/problem/spring/advice/validation/OpenApiValidationAdviceTrait.java)   | [`400 Bad Request`](https://httpstatus.es/400)  | *Derived* from exception   |\n\nThese advices are autoconfigured as bean \n[**`OpenApiValidationExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/OpenApiValidationExceptionHandler.java) if following conditions are true\n* `swagger-request-validator-spring-webmvc-2.34.x.jar` is detected in classpath \n* At least one of `problem.open-api.req-validation-enabled` or `problem.open-api.res-validation-enabled` is set as `true`\n* A valid OpenAPI Spec is provided as config `problem.open-api.path`\n\n\u003e [!NOTE]\n\u003e It is available for Spring Web applications only, not for Spring Webflux application\n\n## Configurations\n\nThe [`NoHandlerFoundAdviceTrait`](src/main/java/com/ksoot/problem/spring/advice/routing/NoHandlerFoundAdviceTrait.java)\nin addition also requires the following configuration:\n\n```properties\nspring.mvc.throw-exception-if-no-handler-found=true\n```\n\nWhile using Dao advice, set database platform as follows, set value as per the database being used.\n```properties\nspring.jpa.database=POSTGRESQL\n```\nRefer to [`Database`](src/main/java/com/ksoot/problem/spring/advice/dao/Database.java) for the list of database vendors such as \n`DB2`, `DERBY`, `H2`, `HANA`, `HSQL`, `INFORMIX`, `MYSQL`, `ORACLE`, `POSTGRESQL`, `SQL_SERVER`, `SYBASE`\n\n\u003e [!NOTE]\n\u003e [**`ConstraintNameResolver`**](src/main/java/com/ksoot/problem/spring/advice/dao/ConstraintNameResolver.java) is implemented for Postgres, SQL Server and MongoDB only as of now.\nIf any other relational database is used then respective [**`ConstraintNameResolver`**](src/main/java/com/ksoot/problem/spring/advice/dao/ConstraintNameResolver.java) need to be implemented and defined as a bean.\n\nMake sure to disable the `ErrorMvcAutoConfiguration` as follows\n\n```java\n@EnableAutoConfiguration(exclude = ErrorMvcAutoConfiguration.class)\n```\nor in `application.properties` as follows\n```properties\nspring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration\n```\n\nSpecify message source bundles as follows. Make sure to include `i18n/problems` bundled in the library, as it \nhas default messages for certain exception. And it should be last in the list of `basenames`, \nso that it has the lowest priority and any default messages coming from `problems.properties` can be overridden \nby specifying the property with different value in application's `errors.properties`\n```properties\nspring.messages.basename=i18n/errors,i18n/problems\nspring.messages.use-code-as-default-message=true\n```\nif `use-code-as-default-message` is set to `false` and the message is not found in any of the `properties` file \nthen it will throw `NoSuchMessageException` complaining that no message is found for given code. \nSo if it is intended to enforce all messages for exceptions to be specified in `properties` file, set it to `false`, \nbut not recommended.\nTo be on safer side, it's recommended to keep it `true`, in that case if some message is not found, \nthe message key is taken as its value, which can be updated later into `properties` file, once noticed.\n\n\u003e [!IMPORTANT]\nSpring boot 3 also provides Problem details support which must not be enabled otherwise it will shadow all `ControllerAdvice`'s provided by this library.\nBy default `spring.mvc.problemdetails.enabled` is `false`, so it must not be set to `true`\n\n## Problem Properties\n**Following are the configurations** to customize default behaviour of `spring-boot-problem-handler`.\n```properties\nproblem.enabled=true\nproblem.type-url=http://localhost:8080/problems/help.html\nproblem.debug-enabled=false\nproblem.stacktrace-enabled=false\nproblem.cause-chains-enabled=false\n#problem.jackson-module-enabled=false\n#problem.dao-advice-enabled=false\n#problem.security-advice-enabled=false\nproblem.open-api.path=/oas/api.json\nproblem.open-api.exclude-patterns=/api/states,/api/states/**,/api/employees,/api/employees/**,/problems/**\nproblem.open-api.req-validation-enabled=true\nproblem.open-api.res-validation-enabled=false\nproblem.tracing.enabled=false\nproblem.tracing.trace-id=X-trace-id\nproblem.tracing.strategy=HEADER\n```\n\n* `problem.enabled`:- To enable or disable autoconfiguration, default is `true`. \n  In case consumer applications are interested to avail advices but want full control over configurations, \n  then it can be set to `false` and required advices can be configured as Spring beans similar to how they are autoconfigured.\n* `problem.type-url`:- The base `URL` for **Help page** describing errors. For different exceptions respective code for exception is appended to it followed by a `#`\n* `problem.debug-enabled`:- To enable or disable debugging i.e. to get the message resolvers to specify the error messages in `properties` files. \n  Elaborated in [*Usage*](https://github.com/officiallysingh/spring-boot-problem-handler#usage) section. Default is `false`.\n* `problem.stacktrace-enabled`:- To enable or disable Stacktraces, default is `false`. \n  Should only be set to `true` for debugging purposes only on local or lower environments, otherwise the application internals may be exposed.\n* `problem.cause-chains-enabled`:- To enable or disable cause chains, default is `false`. \n  Elaborated in [*Usage*](https://github.com/officiallysingh/spring-boot-problem-handler#usage) section.\n* `problem.jackson-module-enabled`:- To enable or disable Jackson Problem Module autoconfiguration, default is `true`.\n  Set it to `false` in case consumer application needs to define Serialization/Deserialization explicitly. \n  Or if `Gson` is to be used instead of `Jackson`. If disabled, the required serializers need to be defined by consumer application.\n* `problem.dao-advice-enabled`:- To enable or disable Dao advice autoconfiguration, default is `true`. \n  Set it to `false` in case consumer application need to define Dao advice configurations explicitly.\n* `problem.security-advice-enabled`:- To enable or disable Security advice autoconfiguration, default is `true`.\n  Set it to `false` in case a consumer application needs to define Security advice configurations explicitly.\n* `problem.open-api.path`:- OpenAPI Specification path. Ideally should be in classpath and start with`/`.\n  If not specified, OpenAPI Specification validation is not enabled.\n* `problem.open-api.exclude-patterns`:- List of `URI` Ant patterns to be excluded from OpenAPI specification validation. Default is empty.\n* `problem.open-api.req-validation-enabled`:- To enable or disable OpenAPI specification validation for request, default is `false`.\n* `problem.open-api.res-validation-enabled`:- To enable or disable OpenAPI specification validation for response, default is `false`.\n* `problem.tracing.enabled`:- Whether to enable Tracing support, default is `false`.\n* `problem.tracing.trace-id`:- Attribute name in error response body or Header name for Trace Id, default is `X-trace-id`.\n* `problem.tracing.strategy`:- Whether to add Trace Id in header or body of error response, default is `HEADER`.\n\n## Error Key\nThe main concept behind specifying the error attributes in `properties` file is **Error key**, which is mandatory to be unique for each error scenario.\n**It is either derived or specified by application** while throwing exception and used to externalize the error attributes in `properties` file. \n\nFor example, if error key for some exception is `some.error.key`, then error response attributes can be specified in `properties` file as follows.\n```properties\ncode.some.error.key=some-error\ntitle.some.error.key=Some Error\ndetail.some.error.key=Something has gone wrong, please look into the logs for details\n```\nIn case of exceptions for which advices are not defined, status also need to be specified in `properties` file as follows. It is elaborated in below sections.\n```properties\nstatus.some.error.key=400\n```\n\n\u003e [!WARNING]\n\u003e The derived Error keys may change in cases of code refactoring.\n\u003e Because derived Error keys may contain the class names, method names and class property names or database constraint or index name.\n\u003e So in such case verify and do necessary updates in error message `properties` files.\n\n* When OpenAPI Spec is changed, the error keys for OpenAPI spec validation errors may change.\n* When controller method name changes or controller argument Object class name or any of its property name changes then `jakarta.validation.*` violation error keys may change.\n* When database constraint name or index name changes then any `DuplicateKeyException` or `DataIntegrityViolationException` error key may change.\n\n## Error response\nFollowing is an example response body for an error.\n```json\n{\n  \"type\":\"http://localhost:8080/problems/help.html#XYZ-001\",\n  \"title\":\"Internal Server Error\",\n  \"status\":500,\n  \"detail\":\"A job instance already exists and is complete for parameters={'date':'{value=2023-08-13, type=class java.time.LocalDate, identifying=true}'}.  If you want to run this job again, change the parameters.\",\n  \"instance\":\"/api/myjob\",\n  \"method\":\"PUT\",\n  \"timestamp\":\"2023-08-14T20:45:45.737227+05:30\",\n  \"code\":\"XYZ-001\"\n}\n```\nResponse Header when service is configured for Json `HttpMessageConverters`\n```text\ncontent-type: application/problem+json\n```\nResponse Header when service is configured for XML `HttpMessageConverters`\n```text\ncontent-type: application/problem+xml\n```\n\n**Description**\n* `type`:- A `URI` reference that identifies the problem type.  When dereferenced, it provides human-readable documentation for this error.\n  If not set `about:blank` is taken as default.\n* `title`:- A short, human-readable summary of the error such as `Bad Request`.\n* `status`:- The HTTP status code, int value such as `500`.\n* `detail`:- A human-readable explanation specific to this occurrence of error.\n* `instance`:- The API `URI` reference where this error has occurred.\n* `method`:- `HttpMethod` for given `instance` where this error has occurred.\n* `timestamp`:- `OffsetDateTime` of occurrence of this error.\n* `code`:- Unique `String` code for this error, should not contain spaces or special characters except '_' and '-'. \n  Used in `type`. Commonly used to set unique codes for different business error scenarios.\n\n## Message resolvers\nTo know how to define the error attributes in the properties file, enable debugging as follows.\n```properties\nproblem.debug-enabled=true\n```\nNow the error response itself would contain the resolvers for respective attributes, as follows.\n`codes` in the resolvers could be one or multiple. \nFor example in case of `ConstraintViolationException` `codes` would be multiple in order of most specific towards least specific.\n```json\n{\n  \"type\":\"http://localhost:8080/problems/help.html#XYZ-001\",\n  \"title\":\"Internal Server Error\",\n  \"status\":500,\n  \"detail\":\"A job instance already exists and is complete for parameters={'date':'{value=2023-08-13, type=class java.time.LocalDate, identifying=true}'}.  If you want to run this job again, change the parameters.\",\n  \"instance\":\"/api/myjob\",\n  \"method\":\"PUT\",\n  \"timestamp\":\"2023-08-14T20:51:43.993249+05:30\",\n  \"code\":\"XYZ-001\",\n  \"codeResolver\":{\n    \"codes\":[\n      \"code.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException\"\n    ],\n    \"defaultMessage\":\"500\",\n    \"arguments\":null\n  },\n  \"titleResolver\":{\n    \"codes\":[\n      \"title.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException\"\n    ],\n    \"defaultMessage\":\"Internal Server Error\",\n    \"arguments\":null\n  },\n  \"detailResolver\":{\n    \"codes\":[\n      \"detail.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException\"\n    ],\n    \"defaultMessage\":\"A job instance already exists and is complete for parameters={'date':'{value=2023-08-13, type=class java.time.LocalDate, identifying=true}'}.  If you want to run this job again, change the parameters.\",\n    \"arguments\":null\n  },\n  \"statusResolver\":{\n    \"codes\":[\n      \"status.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException\"\n    ],\n    \"defaultMessage\":\"500\",\n    \"arguments\":null\n  }\n}\n```\nRespective codes for corresponding attribute can be copied, and a message can be specified for the same in `properties` file.\n\n\u003e [!NOTE]\n\u003e `org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException` i.e. fully qualified name of exception is the [*Error key*](https://github.com/officiallysingh/spring-boot-problem-handler#error-key) in above case.\n **This scenario also covers all the exceptions for which advices are not defined**.\nBut additionally `HttpStatus` need to be specified in `properties` file as it has not been specified anywhere in code because `ControllerAdvice` is not defined,\nif status not given even in `properties` file `HttpStatus.INTERNAL_SERVER_ERROR` is taken as default.\nHence the error response can be specified as follows.\n\n```properties\nstatus.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException=409\ncode.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException=Some code\ntitle.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException=Some title\ndetail.org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException=Some message details\n```\n\nTo minimize the number of properties following defaults are taken if `HttpStatus` is specified as `status.`(error key) property.\n* **Code** is taken as specified `HttpStatus`'s int code e.g., if `HttpStatus` is given as `EXPECTATION_FAILED` then the Code default would be `417`\n* **Title** is taken as specified `HttpStatus`'s reason phrase e.g., if `HttpStatus` is given as `EXPECTATION_FAILED` then the Title default would be `Expectation Failed`\n* **Detail** default is taken from thrown exception's `exception.getMessage()`.\n\n\u003e [!NOTE]\n\u003e `status.`(error key) property is considered only for exceptions where no explicit advice is defined, \notherwise `HttpStatus` is specified in the java code.\n\n## Message internationalization\nThe error messages are read from configured resource bundles, \nby [ProblemMessageProvider](src/main/java/com/ksoot/problem/spring/config/ProblemMessageProvider.java) \nfor current request `Locale` given by `LocaleContextHolder.getLocale()`.\nBy default, spring boot autoconfigures `AcceptHeaderLocaleContextResolver` to get `Locale` from `Accept-Language` request header.\n\nIf the `Accept-Language` header is `fr` then the error messages are read from `_fr.properties` file from configured resource bundles.\nFollowing request in demo project [**`problem-handler-web-demo`**](https://github.com/officiallysingh/problem-handler-web-demo)\n\n```curl\ncurl --location 'http://localhost:8080/api/states' \\\n--header 'accept: */*' \\\n--header 'Content-Type: application/json' \\\n--header 'Accept-Language: fr' \\\n--header 'Cookie: JSESSIONID=9EF49EB9744759DF7A1EE71BD2154A53' \\\n--data '{\n  \"name\": \"Haryana\",\n  \"gstCode\": \"6\"\n}'\n```\n\nreturns following error message in French language as specified in \n[**`errors_fr.properties`**](https://github.com/officiallysingh/problem-handler-web-demo/blob/main/src/main/resources/i18n/errors_fr.properties) file.\n```properties\n```json\n{\n    \"type\": \"http://localhost:8080/problems/help.html#401\",\n    \"title\": \"Non autorisé\",\n    \"status\": 401,\n    \"detail\": \"Le jeton d'autorisation de l'en-t�te est manquant ou invalide\",\n    \"instance\": \"/api/states\",\n    \"method\": \"POST\",\n    \"timestamp\": \"2025-04-19T14:53:30.285582+05:30\",\n    \"code\": \"401\"\n}\n```\n\n\u003e [!IMPORTANT]\n\u003e`LocaleContextHolder.getLocale()` gets the current request `Locale` from `ThreadLocal`, which does not work in case of reactive applications (Webflux) \n\u003e as each operator in reactive pipeline can execute in a different thread, and the context is not inherited from calling thread, but explicitly need to be propagated.  \n\u003e Similar to [**`ReactiveSecurityContextHolder`**](https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/context/ReactiveSecurityContextHolder.html) there is no reactive context holder for `Locale`.\n\nFor demo purpose, defining the following bean serves the purpose, but not recommended in production.\n```java\n  @Bean\npublic HttpHandler httpHandler(ApplicationContext applicationContext) {\n    LocaleContextHolder.getLocaleContext().getLocale();\n    HttpHandler delegate = WebHttpHandlerBuilder\n            .applicationContext(applicationContext).build();\n    return new HttpWebHandlerAdapter(((HttpWebHandlerAdapter) delegate)) {\n        @Override\n        protected ServerWebExchange createExchange(ServerHttpRequest request,\n                                                   ServerHttpResponse response) {\n            ServerWebExchange serverWebExchange = super\n                    .createExchange(request, response);\n            LocaleContext localeContext = serverWebExchange.getLocaleContext();\n            if (localeContext != null) {\n                LocaleContextHolder.setLocaleContext(localeContext, true);\n            }\n            return serverWebExchange;\n        }\n    };\n}\n```\n\nYou can define your own [**`ProblemMessageProvider`**](src/main/java/com/ksoot/problem/spring/config/ProblemMessageProvider.java)  bean as follows, that should be able to find current request `Locale` somehow.\n```java\n@Bean\nProblemMessageProvider problemMessageProvider(final MessageSource messageSource) {\n    return new YourReactiveProblemMessageProvider(messageSource);\n}\n```\n\n## Tracing\n[**`ProblemMicrometerTraceProvider`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/ProblemMicrometerTraceProvider.java) \nis the default implementation of [**`TraceProvider`**](src/main/java/com/ksoot/problem/core/TraceProvider.java) that uses Micrometer Tracing.\nIt is enabled if \n- `io.micrometer.tracing.Tracer` class is available in the classpath.\n- `io.micrometer.tracing.Tracer` bean is available in the application context.\n- In case above two conditions are not met and tracing is still enabled, trace-id would be set as `null`\n- `problem.tracing.enabled` is set to true\n\nIf required, you can provide your own implementation of [**`TraceProvider`**](src/main/java/com/ksoot/problem/core/TraceProvider.java) \nin cases where you want to customize the Trace Id generation or retrieval process or using some other library than `micrometer-tracing`.\n\n### Trace Id as Body Attribute in error response attribute\nSet the following configuration in `application.properties` or `application.yml` file\n```properties\nproblem.tracing.enabled=true\nproblem.tracing.trace-id=traceId  // Or any other name of attribute, as you wish\nproblem.tracing.strategy=BODY\n```\n### Trace Id as Header in error response\n[ProblemTracingWebFilter](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/ProblemTracingWebFilter.java) sets the Trace Id in Header for Servlet Web application \nand [ProblemTracingWebFluxFilter](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/webflux/ProblemTracingWebFluxFilter.java) do the same for WebFlux application.\n\n## Creating and throwing exceptions\n\nApart from exceptions thrown by frameworks or java, every application needs to throw custom exceptions.\n[**`ApplicationProblem`**](src/main/java/com/ksoot/problem/core/ApplicationProblem.java) and\n[**`ApplicationException`**](src/main/java/com/ksoot/problem/core/ApplicationException.java) \nclasses are available in the library to throw an unchecked or checked exception respectively.\n\n\u003e [**`Problems`**](src/main/java/com/ksoot/problem/core/Problems.java) **is the central static helper class to create \nProblem instances and throw either checked or unchecked exceptions**, as demonstrated below.\nIt provides multiple fluent methods to build and throw exceptions.\n\n* The simplistic way is to just specify a unique error key and `HttpStatus`.\n```java\nthrow Problems.newInstance(\"sample.problem\").throwAble(HttpStatus.EXPECTATION_FAILED);\n```\nError response attributes `code`, `title` and `detail` are expected from the message source (`properties` file) available as follows.\nNotice the [*Error key*](https://github.com/officiallysingh/spring-boot-problem-handler#error-key) **sample.problem** in the following properties\n\n```properties\ncode.sample.problem=AYX123\ntitle.sample.problem=Some title\ndetail.sample.problem=Some message details\n```\n\n\u003e [!WARNING]\n\u003e It uses Spring's `MessageSource` to resolve placeholders in message template. \n\u003e You should be aware that the single quote character (') fulfils a special purpose inside message patterns. \n\u003e The single quote is used to represent a section within the message pattern that will not be formatted. \n\u003e A single quote itself must be escaped by using two single quotes ('').\n\nBut exceptions come with some default attributes as follows, to minimize the number of properties required to be defined in `properties` file\n\nIf the messages are not found in `properties` files, defaults are taken as follows.\n* **Code** is taken as specified `HttpStatus`'s int code e.g. if `HttpStatus` is given as `EXPECTATION_FAILED` then the Code default would be `417`\n* **Title** is taken as specified `HttpStatus`'s reason phrase e.g. if `HttpStatus` is given as `EXPECTATION_FAILED` then the Title default would be `Expectation Failed`\n* **Detail** default is taken as thrown exception's `exception.getMessage()`\n\nThere are multiple other methods available while creating and throwing exceptions in [**`Problems`**](src/main/java/com/ksoot/problem/core/Problems.java), \nfor details refers to its source code and java docs. \n```java\nthrow Problems.newInstance(\"sample.problem\")\n    .defaultDetail(\"Default details if not found in properties file with parma1: {0} and param2: {1}\")\n    .detailArgs(\"P1\", \"P2\")\n    .cause(new IllegalStateException(\"Artificially induced illegal state\"))\n    .throwAble(HttpStatus.EXPECTATION_FAILED); // .throwAbleChecked(HttpStatus.EXPECTATION_FAILED)\n```\nThe above code snippet would throw unchecked exception, though not recommended but to throw checked exception,\nuse `throwAbleChecked` as terminal operation as highlighted in java comment above.\n\nThe attributes corresponding to error key `sample.problem` can be provided in `properties` file as follows.\n```properties\ncode.sample.problem=404\ntitle.sample.problem=Some title\ndetail.sample.problem=Some details with param one: {0} and param other: {1}\n```\n\n* To throw exception with hardcoded attributes.\n```java\nProblem problem = Problems.newInstance(\"111\", \"Dummy\", \"Hardcode attributes broblem\").build();\nthrow problem;\n```\n\n* To programmatically add dynamic attributes to error response at runtime. Notice the method `parameter`\n```java\nProblems.newInstance(\"3456\", \"Bad Request\", \"Invalid request received, Please retry with correct input\")\n    .parameter(\"additional-attribute\", \"Some additional attribute\").build();\nthrow problem;\n```\n\n* Applications may also define `enum`s implementing [**`ErrorType`**](src/main/java/com/ksoot/problem/core/ErrorType.java) interface \nwith attributes for error scenarios and creating exceptions as follows. Default error attributes `detail`, `status` etc. can be customized in `properties` file for given `errorKey`, \notherwise the enum only is enough.\n```java\n@Getter\npublic enum AppErrors implements ErrorType {\n\n  REMOTE_HOST_NOT_AVAILABLE(\"remote.host.not.available\",\n      \"Looks like something wrong with remote host: {0}\", HttpStatus.SERVICE_UNAVAILABLE);\n  // All other error scenarios could be added here\n  \n  private final String errorKey;\n  private final String defaultDetail;\n  private final HttpStatus status;\n\n  AppErrors(final String errorKey, final String defaultDetail, final HttpStatus status) {\n    this.errorKey = errorKey;\n    this.defaultDetail = defaultDetail;\n    this.status = status;\n  }\n}\n```\n```java\nApplicationProblem problem = Problems.newInstance(AppErrors.REMOTE_HOST_NOT_AVAILABLE)\n        .detailArgs(\"http://some.remote.host.com\").throwAble();\nthrow problem;\n```\n\n* Sometimes it is not desirable to throw exceptions as they occur, but to collect them to throw at a later point in execution.\nOr to throw multiple exceptions together.That can be done as follows.\n```java\nApplicationException exceptionOne = Problems.newInstance(\"sample.problem.one\").throwAbleChecked();\nApplicationProblem exceptionTwo = Problems.newInstance(AppErrors.REMOTE_HOST_NOT_AVAILABLE)\n        .detailArgs(\"http://some.remote.host.com\").throwAble();\n\nMultiProblem problems = Problems.ofExceptions(HttpStatus.MULTI_STATUS, exceptionOne, exceptionTwo);\n\nException exceptionThree = new IllegalStateException(\"Just for testing exception\");\nproblems.add(exceptionThree);\n\nProblem problem = Problems.newInstance(\"111\", \"Dummy\", \"Hardcode attributes broblem\").build();\nproblems.add(problem);\n\nthrow problems;\n```\n\n* `HttpStatus` can also be set over custom exception as follows, the same would reflect in error response and \nother error attributes default would be derived by given `HttpStatus` attribute in `@ResponseStatus`\n```java\n@ResponseStatus(HttpStatus.NOT_IMPLEMENTED)\nprivate static final class MyException extends RuntimeException {\n    public MyException() {\n    }\n\n    public MyException(final Throwable cause) {\n        super(cause);\n    }\n}\n```\n\n## Stack traces\nSet following property to `true` to get the `stacktrace` in error response, \nshould only be used on local for debugging purpose and strictly prohibited elsewhere as it may expose application internals.\n```properties\nproblem.stacktrace-enabled=true\n```\nExample response\n```json\n{\n  \"type\":\"http://localhost:8080/problems/help.html#XYZ-001\",\n  \"title\":\"Internal Server Error\",\n  \"status\":500,\n  \"detail\":\"A job instance already exists and is complete for parameters={'date':'{value=2023-08-13, type=class java.time.LocalDate, identifying=true}'}.  If you want to run this job again, change the parameters.\",\n  \"instance\":\"/api/myjob\",\n  \"method\":\"PUT\",\n  \"timestamp\":\"2023-08-14T21:01:56.378749+05:30\",\n  \"code\":\"XYZ-001\",\n  \"statcktrace\":[\n    \"org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:159)\",\n    \"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\",\n    \"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)\",\n    \"java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\",\n    \"java.base/java.lang.reflect.Method.invoke(Method.java:568)\",\n    \".......\",\n    \"..............\",\n    \"org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\",\n    \"org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\",\n    \"java.base/java.lang.Thread.run(Thread.java:833)\"\n  ]\n}\n```\n\n## Cause chains\nAn exception may have a cause, which in tern may also have another and so on.\nThe complete cause chain can also be viewed in error response, again it should just be used for local debugging purposes only.\n\n```properties\nproblem.cause-chains-enabled=true\n```\nExample response\n```json\n{\n  \"type\":\"http://localhost:8080/problems/help.html#XYZ-001\",\n  \"title\":\"Not Implemented\",\n  \"status\":501,\n  \"detail\":\"expected\",\n  \"instance\":\"/problems/handler-throwable-annotated-cause\",\n  \"method\":\"GET\",\n  \"timestamp\":\"2023-08-14T22:09:56.284473+05:30\",\n  \"code\":\"XYZ-001\",\n  \"cause\":{\n    \"code\":\"501\",\n    \"title\":\"Not Implemented\",\n    \"detail\":\"Something has gone wrong\",\n    \"cause\":{\n      \"code\":\"501\",\n      \"title\":\"Not Implemented\"\n    }\n  }\n}\n```\n\n## Customizations\n### Customize error response\nThe error response is totally customizable by defining a bean of type [**`ErrorResponseBuilder`**](src/main/java/com/ksoot/problem/core/ErrorResponseBuilder.java) demonstrated as follows.\n* If it is required to customize the error response attribute names, it can be done by implementing custom serialization for `ProblemDetail` using Jackson Mixin.\n* Or define custom error response class as follows.\n```java\n@Getter\n@AllArgsConstructor(staticName = \"of\")\npublic class CustomErrorResponse {\n    private HttpStatus status;\n    private String message;\n}\n```\n* And define custom error response builder class bean to return the custom error response as follows.\n\n\u003e For Spring Web applications\n```java\n@Component\nclass CustomErrorResponseBuilder implements ErrorResponseBuilder\u003cNativeWebRequest, ResponseEntity\u003cCustomErrorResponse\u003e\u003e {\n\n    @Override\n    public ResponseEntity\u003cCustomErrorResponse\u003e buildResponse(final Throwable throwable, final NativeWebRequest request,\n                                                           final HttpStatus status, final HttpHeaders headers, final Problem problem) {\n        CustomErrorResponse errorResponse = CustomErrorResponse.of(status, problem.getDetail());\n        ResponseEntity\u003cCustomErrorResponse\u003e responseEntity = ResponseEntity\n            .status(status).headers(headers).contentType(MediaTypes.PROBLEM).body(errorResponse);\n        return responseEntity;\n    }\n}\n```\n\n\u003e For Spring Webflux applications\n```java\n@Component\nclass CustomErrorResponseBuilder implements ErrorResponseBuilder\u003cServerWebExchange, Mono\u003cResponseEntity\u003cCustomErrorResponse\u003e\u003e\u003e {\n\n    @Override\n    public Mono\u003cResponseEntity\u003cCustomErrorResponse\u003e\u003e buildResponse(final Throwable throwable, final ServerWebExchange request,\n                                                           final HttpStatus status, final HttpHeaders headers, final Problem problem) {\n        CustomErrorResponse errorResponse = CustomErrorResponse.of(status, problem.getDetail());\n        ResponseEntity\u003cCustomErrorResponse\u003e responseEntity = ResponseEntity\n            .status(status).headers(headers).contentType(MediaTypes.PROBLEM).body(errorResponse);\n        return Mono.just(responseEntity);\n    }\n}\n```\n\n### Customize or Override advices\nAny autoconfigured advice can be customized by overriding the same and providing a different implementation. \nMake sure to add annotation `@Order(Ordered.HIGHEST_PRECEDENCE)` over the class, \nIt makes this handler to take precedence over the fallback advice which handles `Throwable` i.e. for all exceptions for which no `ControllerAdvice`s are defined.  \nIn case of Constraint Violation exceptions, the `errorKey` is derived from the field name, \nbut in cases where field name is customized using `@JsonProperty`, \n`MethodArgumentNotValidException`'s advice may need to be customized to use `@JsonProperty` instead of class's field name in dynamically generated `erroKey` as follows\n\n\u003e For Spring Web applications\n```java\n@ControllerAdvice\n@Order(Ordered.HIGHEST_PRECEDENCE) // Important to note\nclass CustomMethodArgumentNotValidExceptionHandler implements MethodArgumentNotValidAdviceTrait\u003cNativeWebRequest, ResponseEntity\u003cProblemDetail\u003e\u003e {\n\n    @Override\n    public ViolationVM handleFieldError(final FieldError fieldError, final Throwable exception) {\n        String field = fieldError.getField();\n\n        try {\n            if (fieldError.contains(ConstraintViolation.class)) {\n                final ConstraintViolation\u003c?\u003e violation = fieldError.unwrap(ConstraintViolation.class);\n                final Field declaredField = violation.getRootBeanClass().getDeclaredField(fieldError.getField());\n                final JsonProperty annotation = declaredField.getAnnotation(JsonProperty.class);\n\n                if (annotation != null \u0026\u0026 annotation.value() != null \u0026\u0026 !annotation.value().isEmpty()) {\n                    field = annotation.value();\n                }\n            }\n        } catch (Exception ignored) {\n            // Ignored\n        }\n\n        HttpStatus status = defaultConstraintViolationStatus();\n        ProblemMessageSourceResolver codeResolver =\n                ProblemMessageSourceResolver.of(\n                        ProblemConstant.CONSTRAINT_VIOLATION_CODE_CODE_PREFIX, fieldError, status.value());\n        ProblemMessageSourceResolver messageResolver =\n                ProblemMessageSourceResolver.of(\n                        ProblemConstant.CONSTRAINT_VIOLATION_DETAIL_CODE_PREFIX, fieldError);\n        return createViolation(codeResolver, messageResolver, field);\n    }\n}\n```\n\n\u003e For Spring Webflux applications\n```java\n@ControllerAdvice\n@Order(Ordered.HIGHEST_PRECEDENCE) // Important to note\nclass CustomMethodArgumentNotValidExceptionHandler implements MethodArgumentNotValidAdviceTrait\u003cServerWebExchange, Mono\u003cResponseEntity\u003cProblemDetail\u003e\u003e\u003e {\n\n  public Mono\u003cResponseEntity\u003cProblemDetail\u003e\u003e handleMethodArgumentNotValid(final MethodArgumentNotValidException exception, final ServerWebExchange request) {\n    // It remains the same as implemented for Spring web, above\n  }\n}\n```\n\n## Define new advices\nThere should not be any need to create any custom exception hence new advices, but if there is a pressing need to do so,\ncustom exception can be created and corresponding custom `ControllerAdvice` implementing [**`AdviceTrait`**](src/main/java/com/ksoot/problem/spring/advice/AdviceTrait.java) \ncan be defined for the same, though not recommended.\nFollowing example demonstrates new advice for some custom exception `MyCustomException`.\n\n\u003e For Spring Web applications\n```java\n@ControllerAdvice\n@Order(Ordered.HIGHEST_PRECEDENCE) // Important to note\npublic class MyCustomAdvice implements AdviceTrait\u003cNativeWebRequest, ResponseEntity\u003cProblemDetail\u003e\u003e {\n\n    @ExceptionHandler\n    public ResponseEntity\u003cProblemDetail\u003e handleMyCustomException(final MyCustomException exception, final NativeWebRequest request) {\n        // Custome logic to set the error response \n        Problem problem = Problem.code(String.valueOf(HttpStatus.BAD_REQUEST.value())).title(HttpStatus.BAD_REQUEST.getReasonPhrase())\n            .detail(exception.getMessage).build();\n        return create(exception, request, HttpStatus.BAD_REQUEST,\n            problem);\n    }\n}\n```\n\n\u003e For Spring Webflux applications\n```java\n@ControllerAdvice\n@Order(Ordered.HIGHEST_PRECEDENCE) // Important to note\npublic class MyCustomAdvice implements AdviceTrait\u003cServerWebExchange, Mono\u003cResponseEntity\u003cProblemDetail\u003e\u003e\u003e {\n    \n    @ExceptionHandler\n    public Mono\u003cResponseEntity\u003cProblemDetail\u003e\u003e handleMyCustomException(final MyCustomException exception, final ServerWebExchange request) {\n        // It remains the same as implemented for Spring web, above\n    }\n}\n```\n\n## Testing support\nFollowing beans are [**autoconfigured**](src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports) for exception handling\n\n| Configuration class                                                                                                                             | Spring Web         | Spring Webflux |\n|-------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|----------------|\n| [**`ProblemMessageProviderConfig`**](src/main/java/com/ksoot/problem/spring/config/ProblemMessageProviderConfig.java)                           | :white_check_mark: | :white_check_mark:            |\n| [**`ProblemBeanRegistry`**](src/main/java/com/ksoot/problem/spring/config/ProblemBeanRegistry.java)                                             | :white_check_mark: | :white_check_mark:            |\n| [**`ProblemJacksonConfiguration`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/ProblemJacksonConfiguration.java)                 | :white_check_mark: | :white_check_mark:            |\n| [**`ProblemDaoConfiguration`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/ProblemDaoConfiguration.java)                         | :white_check_mark: | :white_check_mark:            |\n| [**`ProblemWebAutoConfiguration`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/ProblemWebAutoConfiguration.java)             | :white_check_mark: | :x:             |\n| [**`WebExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/WebExceptionHandler.java)                             | :white_check_mark: | :x:             |\n| [**`WebSecurityExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/WebSecurityExceptionHandler.java)             | :white_check_mark: | :x:             |\n| [**`WebDaoExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/WebDaoExceptionHandler.java)                       | :white_check_mark: | :x:             |\n| [**`OpenApiValidationExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/web/OpenApiValidationExceptionHandler.java) | :white_check_mark: | :x:             |\n| [**`ProblemWebfluxAutoConfiguration`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/webflux/ProblemWebfluxAutoConfiguration.java) | :x:                | :white_check_mark:            |\n| [**`WebFluxExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/webflux/WebFluxExceptionHandler.java)                 | :x:                | :white_check_mark:            |\n| [**`WebFluxSecurityExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/webflux/WebFluxSecurityExceptionHandler.java) | :x:                | :white_check_mark:            |\n| [**`WebFluxDaoExceptionHandler`**](src/main/java/com/ksoot/problem/spring/boot/autoconfigure/webflux/WebFluxDaoExceptionHandler.java)           | :x:                | :white_check_mark:            |\n\n\nBut the autoconfiguration may not take effect while running Junit test cases, So required configuration classes could be imported for `Controller`s test cases, as follows\n\n\u003e For Spring Web applications\n```java\n@TestConfiguration\n@ImportAutoConfiguration(\n    classes = {\n      ProblemBeanRegistry.class,\n      ProblemMessageProviderConfig.class,\n      ProblemJacksonConfiguration.class,\n      ProblemWebAutoConfiguration.class,\n      WebExceptionHandler.class\n      // WebSecurityExceptionHandler.class // If security is enabled \n      // OpenApiValidationExceptionHandler.class // If OpenAPI validation is enabled     \n    })\npublic class WebTestConfiguration {\n  \n}\n```\n\n\u003e Notice `@ImportAutoConfiguration(classes = {WebTestConfiguration.class})`\n```java\n@WebMvcTest(MyController.class)\n@ImportAutoConfiguration(classes = {WebTestConfiguration.class})\nclass StateControllerTest {\n\n  @Autowired\n  private MockMvc mockMvc;\n\n  @MockBean\n  private MyService myService;\n  \n  @Test\n  @DisplayName(\"Test Create Resource successfully\")\n  public void testCreateResource_Success() throws Exception {\n\n  }\n}\n```\n\n\u003e Similarly for Spring Webflux applications, import following configuration class `@ImportAutoConfiguration(classes = {WebFluxTestConfiguration.class})` in `Controller`s test cases\n```java\n@TestConfiguration\n@ImportAutoConfiguration(\n    classes = {\n      ProblemBeanRegistry.class,\n      ProblemMessageProviderConfig.class,\n      ProblemJacksonConfiguration.class,\n      ProblemWebfluxAutoConfiguration.class,\n      WebFluxExceptionHandler.class\n      // WebFluxSecurityExceptionHandler.class // If security is enabled \n    })\npublic class WebFluxTestConfiguration {\n  \n}\n```\n\n## Example error responses\n**Following are example error responses in different scenarios.**\nThe error response attributes `code`, `title` and `detail` can be customized for each error by specifying\nthe same in `errors.properties` file for different error keys which you can get by setting `problem.debug-enabled=true` in `application.properties` file\n\n### Constraint violations\n#### Jakarta Constraint violations error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#constraint-violations\",\n  \"title\": \"Bad Request\",\n  \"status\": 400,\n  \"detail\": \"Constraint violations has happened, please correct the request and try again\",\n  \"instance\": \"/problems/handler-constraint-violation\",\n  \"method\": \"POST\",\n  \"timestamp\": \"2023-10-29T16:41:59.876471+05:30\",\n  \"code\": \"constraint-violations\",\n  \"violations\": [\n    {\n      \"code\": \"400\",\n      \"detail\": \"User name length should be between 3 and 10\",\n      \"propertyPath\": \"name\"\n    },\n    {\n      \"code\": \"400\",\n      \"detail\": \"Address state name is required\",\n      \"propertyPath\": \"address.state\"\n    },\n    {\n      \"code\": \"400\",\n      \"detail\": \"User designation length should be between 2 and 5\",\n      \"propertyPath\": \"designation\"\n    }\n  ]\n}\n```\n\n#### PostgresDB Unique constraint violation error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#500\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"Employee name must be unique, a record with given name already exists\",\n  \"instance\": \"/api/employees\",\n  \"method\": \"POST\",\n  \"timestamp\": \"2023-10-29T16:44:10.917194+05:30\",\n  \"code\": \"500\"\n}\n```\n\n#### MongoDB Unique constraint violation error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#500\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"State name must be unique\",\n  \"instance\": \"/api/states\",\n  \"method\": \"POST\",\n  \"timestamp\": \"2023-10-29T16:44:44.806613+05:30\",\n  \"code\": \"500\"\n}\n```\n\n#### Invalid Query parameters\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#constraint-violations\",\n  \"title\": \"Bad Request\",\n  \"status\": 400,\n  \"detail\": \"Constraint violations has happened, please correct the request and try again\",\n  \"instance\": \"/problems/handler-invalid-query-strings\",\n  \"method\": \"GET\",\n  \"timestamp\": \"2023-10-29T14:51:37.889537+05:30\",\n  \"code\": \"constraint-violations\",\n  \"violations\": [\n    {\n      \"code\": \"400\",\n      \"detail\": \"must be greater than or equal to 0\",\n      \"propertyPath\": \"page\"\n    }\n  ]\n}\n```\n\n#### Invalid format error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#400\",\n  \"title\": \"Bad Request\",\n  \"status\": 400,\n  \"detail\": \"Invalid date time value or format. Expected a valid date time in ISO format\",\n  \"instance\": \"/problems/handler-datetime-conversion\",\n  \"method\": \"GET\",\n  \"timestamp\": \"2023-10-29T16:05:09.953099+05:30\",\n  \"code\": \"400\",\n  \"propertyPath\": \"dateTime\"\n}\n```\n\n#### File upload max size exceeds error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#400\",\n  \"title\": \"Bad Request\",\n  \"status\": 400,\n  \"detail\": \"Upload file size exceeded the maximum allowed limit: 10485760B\",\n  \"instance\": \"/problems/uploadfile\",\n  \"method\": \"POST\",\n  \"timestamp\": \"2023-10-29T14:31:33.073971+05:30\",\n  \"code\": \"400\"\n}\n```\n\n### Spring framework thrown exceptions\n#### Invalid Media type error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#415\",\n  \"title\": \"Unsupported Media Type\",\n  \"status\": 415,\n  \"detail\": \"Media Type: application/xml Not Acceptable, Supported Media Types are: application/json\",\n  \"instance\": \"/problems/handler-json-body\",\n  \"method\": \"POST\",\n  \"timestamp\": \"2023-10-29T14:45:47.467268+05:30\",\n  \"code\": \"415\"\n}\n```\n\n#### Method not allowed error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#405\",\n  \"title\": \"Method Not Allowed\",\n  \"status\": 405,\n  \"detail\": \"Requested Method: POST not allowed, allowed methods are: GET, PUT\",\n  \"instance\": \"/problems/handler-datetime-conversion\",\n  \"method\": \"POST\",\n  \"timestamp\": \"2023-10-29T16:15:08.916369+05:30\",\n  \"code\": \"405\"\n}\n```\n\n### Programmatically thrown exceptions\n#### Any unhandled Throwable\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#500\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"Expected argument invalid\",\n  \"instance\": \"/problems/handler-throwable\",\n  \"method\": \"GET\",\n  \"timestamp\": \"2023-10-29T14:49:40.998497+05:30\",\n  \"code\": \"500\"\n}\n```\n\n#### Error with dynamic additional attributes\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#3456\",\n  \"title\": \"Bad Request\",\n  \"status\": 400,\n  \"detail\": \"Invalid request received, Please retry with correct input\",\n  \"instance\": \"/problems/throw-problem-with-additional-attribute\",\n  \"method\": \"GET\",\n  \"timestamp\": \"2023-10-29T16:24:37.976724+05:30\",\n  \"code\": \"3456\",\n  \"additional-attribute\": \"Some additional attribute\"\n}\n```\n\n#### Multiple errors\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#207\",\n  \"title\": \"Multi-Status\",\n  \"status\": 207,\n  \"detail\": \"Multi-Status\",\n  \"instance\": \"/problems/throw-multiple-problems\",\n  \"method\": \"GET\",\n  \"timestamp\": \"2023-10-29T16:22:53.363785+05:30\",\n  \"code\": \"207\",\n  \"errors\": [\n    {\n      \"code\": \"500\",\n      \"title\": \"Internal Server Error\",\n      \"detail\": \"Sample error message defined in 'errors.properties'\"\n    },\n    {\n      \"code\": \"503\",\n      \"title\": \"Service Unavailable\",\n      \"detail\": \"Looks like something wrong with remote host: http://some.remote.host.com\"\n    },\n    {\n      \"code\": \"3456\",\n      \"title\": \"Bad Request\",\n      \"detail\": \"Invalid request received, Please retry with correct input\",\n      \"additional-attribute\": \"Some additional attribute\"\n    },\n    {\n      \"code\": \"500\",\n      \"title\": \"Internal Server Error\",\n      \"detail\": \"Just for testing exception\"\n    },\n    {\n      \"code\": \"111\",\n      \"title\": \"Dummy\",\n      \"detail\": \"Hardcode attributes broblem\"\n    }\n  ]\n}\n```\n\n### OpenAPI Specification violation error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#constraint-violations\",\n  \"title\": \"Bad Request\",\n  \"status\": 400,\n  \"detail\": \"Constraint violations has happened, please correct the request and try again\",\n  \"instance\": \"/api/pets\",\n  \"method\": \"POST\",\n  \"timestamp\": \"2023-10-29T16:06:18.335463+05:30\",\n  \"code\": \"constraint-violations\",\n  \"violations\": [\n    {\n      \"code\": \"400\",\n      \"detail\": \"[Path '/id'] Numeric instance is lower than the required minimum (minimum: 1, found: 0)\",\n      \"propertyPath\": \"id\"\n    }\n  ]\n}\n```\n\n### Security error\n```json\n{\n  \"type\": \"http://localhost:8080/problems/help.html#401\",\n  \"title\": \"Unauthorized\",\n  \"status\": 401,\n  \"detail\": \"Either Authorization header bearer token is missing or invalid\",\n  \"instance\": \"/api/employees/1\",\n  \"method\": \"GET\",\n  \"timestamp\": \"2023-10-29T16:08:40.466566+05:30\",\n  \"code\": \"401\"\n}\n```\n\n## Licence\nOpen source [**The MIT License**](http://www.opensource.org/licenses/mit-license.php)\n\n## Authors and acknowledgment\n[**Rajveer Singh**](https://www.linkedin.com/in/rajveer-singh-589b3950/), In case you find any issues or need any support, please email me at raj14.1984@gmail.com.\nPlease give me a :star: if you find it helpful.\n\n## Credits and references\nInspired and taken base code from [**Zalando Problem libraries**](https://github.com/zalando/problem-spring-web)\n\nRefer to [**`problem-handler-web-demo`**](https://github.com/officiallysingh/problem-handler-web-demo) and \n[**`problem-handler-webflux-demo`**](https://github.com/officiallysingh/problem-handler-webflux-demo) \nas examples to see usage and **example error responses** for different kind of errors in **Spring Web** and **Spring Webflux** application respectively.\n\n## Known Issues\n* If an application uses multiple vendor relational databases then the [**`ConstraintNameResolver`**](src/main/java/com/ksoot/problem/spring/advice/dao/ConstraintNameResolver.java) \nmay not work properly, needs further testing. For example, if it is using Postgres and SQL Server both.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofficiallysingh%2Fspring-boot-problem-handler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fofficiallysingh%2Fspring-boot-problem-handler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofficiallysingh%2Fspring-boot-problem-handler/lists"}