13

I am trying to upload the file via Multi part upload of spring boot application. While uploading the file, jetty throws FileNotFound Exception.

Following is the model structure:

private String identifier;
private MultipartFile file;

Following is the config:

@Bean
public MultipartConfigElement multipartConfigElement() {
    MultipartConfigFactory factory = new MultipartConfigFactory();
    factory.setMaxFileSize("500MB");
    factory.setMaxRequestSize("500MB");
    return factory.createMultipartConfig();
}

@Bean
public CommonsMultipartResolver multipartResolver() {
    return new CommonsMultipartResolver();
}

Following call throws the exception:

model.getFile().getInputStream()

Below is the stack trace:

java.io.FileNotFoundException: /tmp/MultiPart7953817223010764667 (No such file or directory)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:146)
    at org.eclipse.jetty.util.MultiPartInputStream$MultiPart.getInputStream(MultiPartInputStream.java:218)
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:253)
//user classes

This issue is intermittent and I am not able to re-produce it with consecutive attempts. Same file gets uploaded successfully for the second time.

Any idea what I am doing wrong here?

Thanks in advance

Darshan Mehta
  • 30,102
  • 11
  • 68
  • 102
  • Do you have any other process cleaning up temp files from `/tmp`? A cron job perhaps? – Vivin Paliath Jun 09 '15 at 17:10
  • I don't think there is any process cleaning up /tmp. We just have a few spring boot apps running on server. – Darshan Mehta Jun 09 '15 at 17:14
  • Have you tried using a different `tmp` dir? It looks like something is getting rid of the file between the time Spring writes it out and then tries to retrieve it. – Vivin Paliath Jun 09 '15 at 17:16
  • I haven't configured temp directory in the application. It is just using the default one. Let me try with different directory. – Darshan Mehta Jun 09 '15 at 17:25
  • @"Darshan Mehta" So? Any updates on the issue? Configuring temp directory helped? – vk23 Jul 07 '17 at 13:55
  • @NoMercy Nope. I ended up upgrading the Spring version and am not seeing this issue anymore. – Darshan Mehta Jul 12 '17 at 14:39
  • 19
    @"Darshan Mehta" I finally fixed it. My problem was that I used @Async method to process MultipartFile, but the incoming request sometimes is destroyed before the file is actually processed. My solution was to read file fully into the memory and then start async processing. – vk23 Jul 14 '17 at 14:09
  • 1
    @vk23 That was my problem too! I guess the documentation should pay more attention on this aspect of work with Multipart file. – Frankie Drake May 27 '19 at 14:44
  • @vk23, can you please explain - 'My solution was to read file fully into the memory and then start async processing'? Does this mean you actually store the file in your storage and then calling the Async method? I don't think that is a good way to process. – Chetan Oswal Nov 24 '20 at 09:02

2 Answers2

13

There can be multiple causes, sprintboot by default stores the Multipart file in some system directory, Once you consume file using file.getInputStream(), doing it again will cause it to happen. As once inputstream is read, spring automatically clears the saved file, leading to file not found exception. Another reason is using @Async while processing the multipart file.

Sahil
  • 131
  • 1
  • 5
  • 1
    "Another reason is using @Async while processing the multipart file." Why is that ? – thevoyager Sep 11 '20 at 08:07
  • see this answer https://stackoverflow.com/questions/36565597/spring-async-file-upload-and-processing – Svirin Sep 22 '21 at 12:51
  • For me what worked was converting MultipartFile into an array of bytes before the async process. `MultipartFile.getBytes()` , not suitable for big files though. Another solution is to copy to absolute path instead of relying on tomcat temp file that gets auto-deleted too soon. – web.learner Jul 08 '22 at 00:57
3

I found a pretty simple way. I used TaskExecutor (a multithreading approach). Noticed that the temp file from tomcat server was getting deleted. So, I created a DTO and pulled important data from the List<MultipartFile> which I needed:-

List<FileDataDTO> files = new ArrayList<>();
        attachments.forEach(attach -> {
            try
            {
                FileDataDTO file = new FileDataDTO();
                file.setFileData(attach.getBytes());
                file.setOriginalName(attach.getOriginalFilename());
                file.setContentType(attach.getContentType());
                files.add(file);
            }
            catch (Exception e)
            {
                logger.error(Constant.EXCEPTION, e);
            }
        });

And then called my Task Executor method. The data then reflected as expected in the new thread.

Chetan Oswal
  • 430
  • 9
  • 21