Multipart file maximum size exception - spring boot embbeded tomcat
Asked Answered
T

7

11

I have set max file size to

multipart.maxFileSize: 1mb
multipart.maxRequestSize: 1mb

This is my controller :

@RequestMapping(method=RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.CREATED)
@Secured(Privileges.CAN_USER_READ)
public void create(@RequestParam("file")final MultipartFile file,Principal principal) throws IllegalStateException, IOException,MultipartException{

    medicalHistoryService.create(new MedicalHistory(file));
}

this is error message

2016-03-03 13:48:24.560  WARN 4992 --- [nio-8080-exec-1] h.c.w.RestResponseEntityExceptionHandler : Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (9288401) exceeds the configured maximum (1048576)

2016-03-03 13:48:25.545  WARN 4992 --- [nio-8080-exec-2] h.c.w.RestResponseEntityExceptionHandler : Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (9288401) exceeds the configured maximum (1048576)

And final result after request with over-sized file is problem loading page. I dont get any other error in stack trace so i am kinda stuck with what is actually going on. Oh yeah i have tried many other solutions such as registering filter, handling exception in ErrorController. Every time i would end up with same result - server crash.

Tomcat crash

EDIT 2

My exception handling class :

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler{

   // 413 MultipartException - file size too big 
@ExceptionHandler({MultipartException.class,FileSizeLimitExceededException.class,java.lang.IllegalStateException.class})
   public ResponseEntity<Object> handleSizeExceededException(final WebRequest request, final MultipartException ex) {
        //log.warn("413 Status Code. File size too large {}", ex.getMessage());
       log.warn(ex.getMessage());
       final ApiError apiError = message(HttpStatus.PAYLOAD_TOO_LARGE, ex);
       return handleExceptionInternal(ex, apiError, new HttpHeaders(), HttpStatus.PAYLOAD_TOO_LARGE, request);
   }
}
Teenyweeny answered 2/3, 2016 at 13:2 Comment(2)
You haven't shown enough of your code. What does handleExceptionInternal do, for example. A minimal, complete, verifiable example will make it easier for people to help you.Bridges
handleExceptionInternal is internal method of ResponseEntityExceptionHandler which is, by documentation " A convenient base class for {@link ControllerAdvice @ControllerAdvice} classes * that wish to provide centralized exception handling".Teenyweeny
T
12

This was tricky. Tomcat property MaxSwallowSize was causing this problem. Apparently it was introduced in one of the recent versions of Tomcat. The whole idea behind it was if Tomcat realized the request was going to be rejected, to terminate the connection anything higher than default 2mb (at least this was my interpretation). Simple overriding this property fixes things. I realize this is not perfect solution, but it is a whole lot better than just terminating connection.

@Bean
public TomcatEmbeddedServletContainerFactory containerFactory() {
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
     factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
        @Override
        public void customize(Connector connector) {
         ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
        }
     });
     return factory;
}
Teenyweeny answered 8/3, 2016 at 10:8 Comment(5)
You just saved me from posting essentially the same code in the question. I doubt I would have discovered the answer, if ever, without many hours trouble so thank you, thank you, thank you.Basipetal
Thank you man, you nailed it, it shoud be part of Springboot documentation.Outgoings
This is no longer the right solution, setting properties like @Estovers said, works.Participial
I disagree with S. Ktifa. The exception is: "org.apache.tomcat.util.http.fileupload.FileUploadBase$" and so I don't believe you are getting to spring and therefore you have to adjust a bean to tell tomcat to complete the request. Updated to the bean...and it's good to go. You need both the spring settings and the bean.Hebron
More correct solution is to set this using application property server.tomcat.max-swallow-size=-1Gnawing
E
27

Started from Spring Boot 2

spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB

See docs

Spring Boot 1.x

Properties should like:
spring.http.multipart.max-file-size=128KB
spring.http.multipart.max-request-size=128KB

See spring boot guides

Estovers answered 15/12, 2016 at 10:40 Comment(3)
For me, this answer solved the problem, without the need to declare any Tomcat specific beans. The problem was that I was using spring.servlet.multipart.max-file-size=128KB instead of spring.http...Grecian
This don't work, at least in Spring Boot 2.1.3. This properties don't exist anymore, check: docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…Tiaratibbetts
@voliveira89, thank you so much for remark! I've edited my answer.Estovers
T
12

This was tricky. Tomcat property MaxSwallowSize was causing this problem. Apparently it was introduced in one of the recent versions of Tomcat. The whole idea behind it was if Tomcat realized the request was going to be rejected, to terminate the connection anything higher than default 2mb (at least this was my interpretation). Simple overriding this property fixes things. I realize this is not perfect solution, but it is a whole lot better than just terminating connection.

@Bean
public TomcatEmbeddedServletContainerFactory containerFactory() {
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
     factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
        @Override
        public void customize(Connector connector) {
         ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
        }
     });
     return factory;
}
Teenyweeny answered 8/3, 2016 at 10:8 Comment(5)
You just saved me from posting essentially the same code in the question. I doubt I would have discovered the answer, if ever, without many hours trouble so thank you, thank you, thank you.Basipetal
Thank you man, you nailed it, it shoud be part of Springboot documentation.Outgoings
This is no longer the right solution, setting properties like @Estovers said, works.Participial
I disagree with S. Ktifa. The exception is: "org.apache.tomcat.util.http.fileupload.FileUploadBase$" and so I don't believe you are getting to spring and therefore you have to adjust a bean to tell tomcat to complete the request. Updated to the bean...and it's good to go. You need both the spring settings and the bean.Hebron
More correct solution is to set this using application property server.tomcat.max-swallow-size=-1Gnawing
P
5

Please add the below lines in application.properties for spring boot version -2.0.1.RELEASE

spring.servlet.multipart.max-file-size=128MB
spring.servlet.multipart.max-request-size=128MB
spring.servlet.multipart.enabled=true

This resolved my issue.

Peeper answered 8/10, 2018 at 6:17 Comment(0)
G
3

Since @SeaBiscuit has provided the correct answer but with Spring boot 2.0.0.RELEASE the class org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory has been removed and replaced by the class org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory. So the code for the new Spring boot 2.0.0 would be

  1. Create a class with any name and annotate it with @Configuration
  2. And put the below code inside that class
@Bean
public TomcatServletWebServerFactory containerFactory() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
        @Override
        public void customize(Connector connector) {
            ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
        }
    });
    return factory;
}

And if you've trouble configuring the maximum file upload size in Spring boot 2.0.0 put below code inside 'application.propertise' file with desired file size in 'MB's

## Image upload limitation properties
spring.servlet.multipart.max-file-size=3MB
spring.servlet.multipart.max-request-size=3MB
Greybeard answered 7/11, 2018 at 11:40 Comment(0)
D
1

I wrote some lines in application.yml to solve this issue like:

spring:
    http:
        multipart:
            max-file-size: 10MB
            max-request-size: 10MB

but it didn't solve the problem. However, adding same lines in application.properties after formatting to single liner way i.e. properties file way then it worked.

Ditch answered 11/3, 2017 at 10:32 Comment(3)
This post isn't an actual attempt at answering the question. Please note Stack Overflow doesn't work like a discussion forum, it is a Q&A site where every post is either a question or an answer to a question. Posts can also have comments - small sentences like this one - that can be used to critique or request clarification from an author. This should be either a comment or a new question.Falzetta
I edited to remove the question in your answer as answers are only supposed to provide answers. You can post that question as a comment or as a new question.Sclerosed
this configuration is deprecated now. instead we have to use spring.servlet.multipart.max-file-size=10MBUnbosom
D
1

I tried all the suggestions above but was still getting an error until I added this:

  server.tomcat.max-swallow-size=-1

in the application.properties file.

Dufrene answered 31/1, 2021 at 9:9 Comment(0)
M
0

The below code worked for me. Add it to spring boot main class:

import javax.servlet.MultipartConfigElement;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;



@SpringBootApplication
@EnableScheduling
@EnableAsync
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    @Bean
    MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize("5MB");
        factory.setMaxRequestSize("5MB");
        return factory.createMultipartConfig();
    }
}
Mendel answered 3/9, 2020 at 10:49 Comment(1)
From Review: Code-only answers are discouraged on Stack Overflow because they don't explain how it solves the problem. Please edit your answer to explain what this code does and how it answers the question, so that it is useful to the OP as well as other users also with similar issues. See: How do I write a good answer?. ThanksKowtow

© 2022 - 2024 — McMap. All rights reserved.