title: Spring MultipartFile causing form validation to not be mapped
body: <p>I'll start by saying my knowledge of Spring is very limited. However, I've been able to work through issues I've faced with it in the past. My newest problem isn't making much sense to me.</p>
  <p>So what I've got is a form which takes attributes for an item to be sold at auction. This form has an optional field which can upload a picture of the item being sold. The image uploading works as is. I noticed my form wasn't actually showing the errors given during validation, so I started looking at what might be causing that. If I remove the MultipartFile from the method signature, the web will correctly show form validation errors if they exist. However, now I don't have the image I need.</p>
  <p>On the flip side, if I add the required = false attribute to the RequestParam on the MultipartFile, my issue persists and when a form doesn't meet the validations set, I'm met with the <a href="https://i.imgur.com/wNGasNH.png" rel="nofollow noreferrer">following</a>.</p>
  <p>The Java side for this method that's supposed to save the item if it's valid or show the validation errors is as follows:</p>
  <pre><code>    @RequestMapping(method = RequestMethod.POST)
      public ModelAndView save(@Valid Item item, @RequestParam(name = &quot;itemImage&quot;, required = false) MultipartFile file,
                           BindingResult result, RedirectAttributes redirect) {
      if (result.hasErrors()) {
          return new ModelAndView(&quot;item/save&quot;, &quot;formErrors&quot;, result.getAllErrors());
      }
  
      boolean isCreate = (null == item.getId());
  
      if (file != null &amp;&amp; !file.isEmpty()) {
          if (isCreate) {
              item = itemService.save(item);
          }
  
          Path directory = Paths.get(itemImageDir + &quot;/&quot; + item.getAuction().getId() + &quot;/&quot; + item.getId());
  
          if (!Files.exists(directory)) {
              try {
                  Files.createDirectories(directory);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
  
          try {
              Files.copy(file.getInputStream(), Paths.get(directory.toString(), file.getOriginalFilename()),
                      StandardCopyOption.REPLACE_EXISTING);
              item.setImageUrl(String.format(&quot;/items/image/%s/%s/%s&quot;, item.getAuction().getId(), item.getId(), file
                      .getOriginalFilename()));
              itemService.save(item);
          } catch (IOException | RuntimeException e) {
              result.addError(new ObjectError(&quot;imageUrl&quot;, &quot;Failed to upload &quot; + file.getOriginalFilename() + &quot; =&gt; &quot;
                      + e.getMessage()));
              return new ModelAndView(&quot;item/save&quot;, &quot;formErrors&quot;, result.getAllErrors());
          }
      } else {
          itemService.save(item);
      }
  
      String message = &quot;Successfully created a new item.&quot;;
      if (!isCreate)
          message = &quot;Item has been successfully updated.&quot;;
  
      redirect.addFlashAttribute(&quot;globalMessage&quot;, message);
      return new ModelAndView(&quot;redirect:/auctions/{item.auction.id}&quot;, &quot;item.auction.id&quot;, item.getAuction().getId());
  }
  </code></pre>
  <p>The view for this page, without all of the extra fluff, looks as so:</p>
  <pre><code>&lt;form id=&quot;auctionForm&quot; class=&quot;col-xs-12&quot; th:action=&quot;@{/items/(item)}&quot; th:object=&quot;${item}&quot;
        action=&quot;#&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;
      &lt;div th:class=&quot;'form-group row'&quot;&gt;
          &lt;label for=&quot;itemImage&quot; class=&quot;control-label col-sm-2&quot;&gt; Image Upload: &lt;/label&gt;
          &lt;div class=&quot;col-sm-4&quot;&gt;
              &lt;input id=&quot;itemImage&quot; type=&quot;file&quot; name=&quot;itemImage&quot;/&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/form&gt;
  </code></pre>
  <p>Extra context for the issue: If I remove the @Valid annotation, the method will be called and won't fail when the form isn't valid. However, when I have @Valid, the controller method is not even hit. Is there a way I can check where it's failing if it isn't getting to the controller? I compared this one controller with all of the others and it seems to follow the same pattern.</p>
  <p>If anyone has any suggestions, I'd be more than grateful. I don't really have any idea what I'm missing, so any suggestions are welcome.</p>