185

I'm trying to remove white label error page, so what I've done was created a controller mapping for "/error",

@RestController
public class IndexController {

    @RequestMapping(value = "/error")
    public String error() {
        return "Error handling";
    }

}

But now I"m getting this error.

Exception in thread "AWT-EventQueue-0" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource   [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Invocation  of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'basicErrorController' bean method 
public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>>  org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletR equest)
to {[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'indexController' bean method

Don't know whether I'm doing anything wrong. Please advice.

EDIT:

Already added error.whitelabel.enabled=false to application.properties file, still getting the same error

Yasitha Waduge
  • 13,180
  • 5
  • 35
  • 42

19 Answers19

270

You need to change your code to the following:

@RestController
public class IndexController implements ErrorController{

    private static final String PATH = "/error";

    @RequestMapping(value = PATH)
    public String error() {
        return "Error handling";
    }

    @Override
    public String getErrorPath() {
        return PATH;
    }
}

Your code did not work, because Spring Boot automatically registers the BasicErrorController as a Spring Bean when you have not specified an implementation of ErrorController.

To see that fact just navigate to ErrorMvcAutoConfiguration.basicErrorController here.

geoand
  • 60,071
  • 24
  • 172
  • 190
  • 1
    Ran into the same into the same issue, I searched the Spring docs but it didn't mention BasicErrorController. This works :) – Mike R Sep 02 '14 at 01:01
  • 4
    I had to go through the source to find this one :-) – geoand Sep 02 '14 at 04:25
  • 1
    Thanks, worked nicely! A small follow-up if you can give any pointers: say we get in this error handler because some exception was thrown in our app (and Spring implicitly sets response code to 500 which is correct); is there an easy way to get hold of that exception here (to include some details in error message returned)? – Jonik Feb 20 '15 at 13:07
  • 1
    Glad you found it useful! Although I haven't tried it, I am pretty sure that you can use the principles found in Spring Boot's `BasicErrorController` (see https://github.com/spring-projects/spring-boot/blob/f97251b9cf80aa5cda21340d6cbcd28852db5c14/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/BasicErrorController.java) to accomplish what you want – geoand Feb 20 '15 at 13:16
  • 3
    Hmm, yes, thanks again! At first I wasn't sure how to get that `ErrorAttributes` object (containing the error details), but then I tried simply @Autowiring it, and it works. What I went with for now: https://gist.github.com/jonikarppinen/662c38fb57a23de61c8b – Jonik Feb 20 '15 at 15:09
  • Hit a snag with the mapping when running as a jar file - basically it seems you have to use just `error` instead of `/error`, otherwise the the error handler is not found when running as `java -jar /path/2/jar` – demaniak Feb 22 '16 at 18:50
  • @geoand - I noticed now the sample here was using a `RestController` - we were using normal MVC `Controller` with the Thymeleaf templating engine. A seemingly related [GitHub Issue here](https://github.com/spring-projects/spring-boot/issues/2057). Any how, in my case, changing route from `/error` to `error` got my custom error page working when ran from IDE and jar. – demaniak Feb 23 '16 at 20:07
  • Implementing BasicErrorController works for errors thrown in GET and POST requests, but exceptions thrown in PUT and DELETE do not get handled by the implemented class (The response comes as a blank body Http 500). Does anyone know what to do to enable catching PUTs and DELETEs? And why are they handled differently than GET and POST? The only place I found this on internet is here (post by zhugw): https://gist.github.com/jonikarppinen/662c38fb57a23de61c8b with no reply to his issue. – tipsytopsy Feb 26 '16 at 03:36
  • 1
    @geoand - This is an issue when using Jetty in Spring boot - works just fine in Tomcat. So it is a bug in Jetty. https://github.com/eclipse/jetty.project/issues/163 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=446039 – tipsytopsy Feb 26 '16 at 17:35
  • @Jonik : I have added the Restcontroller but still I am getting the tomcat error page only when the authentication fails , I am running it as mvn clean tomcat7:run – Chetan Jul 22 '16 at 05:39
  • # Disable Spring Boot's "Whitelabel" default error page, so we can use our own error: whitelabel: enabled: false – anandchaugule Nov 26 '19 at 10:50
  • This fixed my issue! I've just created my project with spring initializer and this error kept popping up... after this fix everything got solved! – Monique Altero Dec 16 '21 at 18:09
52

Spring boot doc 'was' wrong (they have since fixed it) :

To switch it off you can set error.whitelabel.enabled=false

should be

To switch it off you can set server.error.whitelabel.enabled=false

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
willome
  • 3,062
  • 19
  • 32
  • 4
    This will disable the White Label Error Page but spring boot will map the endpoint `/error` anyway. To free the endpoint `/error` set `server.error.path=/error-spring` or some alternative path. – notes-jj Oct 19 '19 at 14:18
46

If you want a more "JSONish" response page you can try something like that:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@RestController
@RequestMapping("/error")
public class SimpleErrorController implements ErrorController {

  private final ErrorAttributes errorAttributes;

  @Autowired
  public SimpleErrorController(ErrorAttributes errorAttributes) {
    Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
    this.errorAttributes = errorAttributes;
  }

  @Override
  public String getErrorPath() {
    return "/error";
  }

  @RequestMapping
  public Map<String, Object> error(HttpServletRequest aRequest){
     Map<String, Object> body = getErrorAttributes(aRequest,getTraceParameter(aRequest));
     String trace = (String) body.get("trace");
     if(trace != null){
       String[] lines = trace.split("\n\t");
       body.put("trace", lines);
     }
     return body;
  }

  private boolean getTraceParameter(HttpServletRequest request) {
    String parameter = request.getParameter("trace");
    if (parameter == null) {
        return false;
    }
    return !"false".equals(parameter.toLowerCase());
  }

  private Map<String, Object> getErrorAttributes(HttpServletRequest aRequest, boolean includeStackTrace) {
    RequestAttributes requestAttributes = new ServletRequestAttributes(aRequest);
    return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
  }
}
okrunner
  • 3,083
  • 29
  • 22
  • 9
    In Spring-Boot v2 the ErrorController and ErrorAttributes classes are in package org.springframework.boot.web.servlet.error and further the ErrorAttributes#getErrorAttributes method signature has changed, please note dependency on Spring-Boot v1 and possibly give hints for v2, thx. – chrisinmtown Nov 13 '18 at 11:21
  • 2
    Change : private Map getErrorAttributes(HttpServletRequest aRequest, boolean includeStackTrace) { RequestAttributes requestAttributes = new ServletRequestAttributes(aRequest); return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace); } By : private Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) { WebRequest webRequest = new ServletWebRequest(request); return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace); } – Rija Ramampiandra Apr 24 '19 at 13:19
  • 5
    An updated version of SimpleErrorController.java considering the comments from above can be found in here > https://gist.github.com/oscarnevarezleal/24030102adbe5dd43d9d53727feacc45 – Oscar Nevarez Sep 20 '19 at 03:07
36

You can remove it completely by specifying:

import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
...
@Configuration
@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})
public static MainApp { ... }

However, do note that doing so will probably cause servlet container's whitelabel pages to show up instead :)


EDIT: Another way to do this is via application.yaml. Just put in the value:

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration

Documentation

For Spring Boot < 2.0, the class is located in package org.springframework.boot.autoconfigure.web.

hoodieman
  • 807
  • 10
  • 15
17

Manual here says that you have to set server.error.whitelabel.enabled to false to disable the standard error page. Maybe it is what you want?

I am experiencing the same error after adding /error mapping, by the way.

Maciej Lach
  • 1,622
  • 3
  • 20
  • 27
Innot Kauker
  • 1,333
  • 1
  • 18
  • 30
  • Yes I've already set error.whitelabel.enabled=false but still getting the same error after adding /error mapping – Yasitha Waduge Aug 18 '14 at 05:46
  • 2
    This will disable the White Label Error Page but spring boot will map the endpoint `/error` anyway. To free the endpoint `/error` set `server.error.path=/error-spring` or some alternative path. – notes-jj Oct 19 '19 at 14:18
13

With Spring Boot > 1.4.x you could do this:

@SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})
public class MyApi {
  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }
}

but then in case of exception the servlet container will display its own error page.

db80
  • 4,157
  • 1
  • 38
  • 38
13

This depends on your spring boot version:

When SpringBootVersion <= 1.2 then use error.whitelabel.enabled = false

When SpringBootVersion >= 1.3 then use server.error.whitelabel.enabled = false

Thomas Marti
  • 940
  • 9
  • 12
sendon1982
  • 9,982
  • 61
  • 44
7

In Spring Boot 1.4.1 using Mustache templates, placing error.html under templates folder will be enough:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Error</title>
</head>

<body>
  <h1>Error {{ status }}</h1>
  <p>{{ error }}</p>
  <p>{{ message }}</p>
  <p>{{ path }}</p>
</body>

</html>

Additional variables can be passed by creating an interceptor for /error

Ecmel Ercan
  • 73
  • 1
  • 2
  • Using this example: https://github.com/paulc4/mvc-exceptions/blob/master/src/main/resources/templates/error.html – e-info128 Nov 26 '16 at 02:36
5

I am using Spring Boot version 2.1.2 and the errorAttributes.getErrorAttributes() signature didn't work for me (in acohen's response). I wanted a JSON type response so I did a little digging and found this method did exactly what I needed.

I got most of my information from this thread as well as this blog post.

First, I created a CustomErrorController that Spring will look for to map any errors to.

package com.example.error;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@RestController
public class CustomErrorController implements ErrorController {

    private static final String PATH = "error";

    @Value("${debug}")
    private boolean debug;

    @Autowired
    private ErrorAttributes errorAttributes;

    @RequestMapping(PATH)
    @ResponseBody
    public CustomHttpErrorResponse error(WebRequest request, HttpServletResponse response) {
        return new CustomHttpErrorResponse(response.getStatus(), getErrorAttributes(request));
    }

    public void setErrorAttributes(ErrorAttributes errorAttributes) {
        this.errorAttributes = errorAttributes;
    }

    @Override
    public String getErrorPath() {
        return PATH;
    }

    private Map<String, Object> getErrorAttributes(WebRequest request) {
        Map<String, Object> map = new HashMap<>();
        map.putAll(this.errorAttributes.getErrorAttributes(request, this.debug));
        return map;
    }
}

Second, I created a CustomHttpErrorResponse class to return the error as JSON.

package com.example.error;

import java.util.Map;

public class CustomHttpErrorResponse {

    private Integer status;
    private String path;
    private String errorMessage;
    private String timeStamp;
    private String trace;

    public CustomHttpErrorResponse(int status, Map<String, Object> errorAttributes) {
        this.setStatus(status);
        this.setPath((String) errorAttributes.get("path"));
        this.setErrorMessage((String) errorAttributes.get("message"));
        this.setTimeStamp(errorAttributes.get("timestamp").toString());
        this.setTrace((String) errorAttributes.get("trace"));
    }

    // getters and setters
}

Finally, I had to turn off the Whitelabel in the application.properties file.

server.error.whitelabel.enabled=false

This should even work for xml requests/responses. But I haven't tested that. It did exactly what I was looking for since I was creating a RESTful API and only wanted to return JSON.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
DJ House
  • 1,307
  • 1
  • 11
  • 14
3

Here's an alternative method which is very similar to the "old way" of specifying error mappings in web.xml.

Just add this to your Spring Boot configuration:

@SpringBootApplication
public class Application implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        factory.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN, "/errors/403.html"));
        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/errors/404.html"));
        factory.addErrorPages(new ErrorPage("/errors/500.html"));
    }

}

Then you can define the error pages in the static content normally.

The customizer can also be a separate @Component, if desired.

rustyx
  • 80,671
  • 25
  • 200
  • 267
3

Spring Boot by default has a “whitelabel” error page which you can see in a browser if you encounter a server error. Whitelabel Error Page is a generic Spring Boot error page which is displayed when no custom error page is found.

Set “server.error.whitelabel.enabled=false” to switch of the default error page

shatakshi
  • 165
  • 8
3

I had a similar issue WhiteLabel Error message on my Angular SPA whenever I did a refresh.

The fix was to create a controller that implements ErrorController but instead of returning a String, I had to return a ModelAndView object that forwards to /

@CrossOrigin
@RestController
public class IndexController implements ErrorController {
    
    private static final String PATH = "/error";
    
    @RequestMapping(value = PATH)
    public ModelAndView saveLeadQuery() {           
        return new ModelAndView("forward:/");
    }

    @Override
    public String getErrorPath() {
        return PATH;
    }
}
2

server.error.whitelabel.enabled=false

Include the above line to the Resources folders application.properties

More Error Issue resolve please refer http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-customize-the-whitelabel-error-page

Community
  • 1
  • 1
  • I tried application.properties in my installation folder which did nothing. The application.properties folder under /src/main/resources is what suganya sudarsan was attempting to convey. It appears to be a "hot read" in Eclipse as well. – Richard Bradley Smith Sep 29 '19 at 20:14
1

I was trying to call a REST endpoint from a microservice and I was using the resttemplate's put method.

In my design if any error occurred inside the REST endpoint it should return a JSON error response, it was working for some calls but not for this put one, it returned the white label error page instead.

So I did some investigation and I found out that;

Spring try to understand the caller if it is a machine then it returns JSON response or if it is a browser than it returns the white label error page HTML.

As a result: my client app needed to say to REST endpoint that the caller is a machine, not a browser so for this the client app needed to add 'application/json' into the ACCEPT header explicitly for the resttemplate's 'put' method. I added this to the header and solved the problem.

my call to the endpoint:

restTemplate.put(url, request, param1, param2);

for above call I had to add below header param.

headers.set("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);

or I tried to change put to exchange as well, in this case, exchange call added the same header for me and solved the problem too but I don't know why :)

restTemplate.exchange(....)
Yusuf
  • 329
  • 3
  • 12
1

Solution posted by geoand works for me. In addition to this, if you want to redirect to any specific page then you may use this.

@RequestMapping(value = PATH)
public void error(HttpServletResponse response) {
    response.sendRedirect("/");   //provide your error page url or home url
}

Full Code snippet below:

@RestController
public class IndexController implements ErrorController{

    private static final String PATH = "/error";

    @RequestMapping(value = PATH)
    public void error(HttpServletResponse response) {
         response.sendRedirect("/");   //provide your error page url or home url
    }

    @Override
    public String getErrorPath() {
        return PATH;
    }
}

PS: Since, unable to edit above answer, hence posting this as new answer.

singhpradeep
  • 1,593
  • 1
  • 12
  • 11
1

Custom error page in JSON format for Spring Boot > 2.3.0

package com.example.api.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;

import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@RestController
public class CustomErrorController implements ErrorController {
    private static final String PATH = "/error";

    @Autowired
    private ErrorAttributes errorAttributes;

    @RequestMapping(PATH)
    public Map<String, Object> error(WebRequest request, HttpServletResponse response) {
        return getErrorAttributes(request, true);
    }

    private Map<String, Object> getErrorAttributes(WebRequest request, boolean includeStackTrace) {
        ErrorAttributeOptions options = ErrorAttributeOptions.defaults()
                .including(ErrorAttributeOptions.Include.MESSAGE)
                .including(ErrorAttributeOptions.Include.EXCEPTION)
                .including(ErrorAttributeOptions.Include.BINDING_ERRORS);
        if(includeStackTrace){
            options = options.including(ErrorAttributeOptions.Include.STACK_TRACE);
        }
        return this.errorAttributes.getErrorAttributes(request, options);
    }
}

Ashish Lahoti
  • 648
  • 6
  • 8
0

Best option would be to create a HTML page (JSP,THYMELEAF) with the name "error.html", it would redirect every whitelable error to this page . You can customize it after .

Arbis Malasi
  • 121
  • 1
  • 6
0

We can easily handle white label error in Java Spring boot. Just add this class in configuration file..

import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebRoutingConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/urlNotFound")
                // the viewName should be specified, in our case we forward to the index.html 
                .setViewName("forward:/index.html");
    }

    @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
        return container -> {
            container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
                    "/urlNotFound"));
        };
    }

}
0

I literally missed to add the @RestController annotation in my code somehow. Silly as it may sound, but worth keeping written down somewhere if you ask me, just in-case if you miss that one in a rush..

@RestController
public class MyApiController implements MyApi {
.
.

SydMK
  • 425
  • 4
  • 12