Abdul Munda bio photo

Abdul Munda

I am Abdul Munda from Toronto, Canada. I am a father, husband, full-stack developer and entrepreneur. Technologies I am most interested in are Ruby on Rails, NodeJS and React

Twitter LinkedIn Github

Handling S3 IncompleteBody error when using asset_sync gem

I was recently trying to move the assets to S3 for a Rails project. I decided to use the asset_sync gem which uploads assets to S3 on the pre-compilation of the assets. Everything worked smoothly for a few files but failed shortly for large asset files. It failed with 400 Bad Request with the message saying "IncompleteBody".

rake aborted!
Excon::Errors::BadRequest: Expected(200) <=< Actual(400 Bad Request)
excon.error.response
  :body          => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>IncompleteBody</Code><Message>The request body terminated unexpectedly</Message><RequestId>5308A1EB2B27126C</RequestId><HostId>fWLX6lpgCA0naOISn774juwtKAs9NHODP5WQHFBX7tVPVrK52OI7wlE8YY5zG/ohtis5cvit8f8=</HostId></Error>"
...

.../gems/excon-0.43.0/lib/excon/middlewares/expects.rb:6:in `response_call'
.../gems/excon-0.43.0/lib/excon/middlewares/response_parser.rb:8:in `response_call'
.../gems/excon-0.43.0/lib/excon/connection.rb:366:in `response'
.../gems/excon-0.43.0/lib/excon/connection.rb:236:in `request'

I took a look at the amazon S3 Error Responses page and it said that it happens when "You did not provide the number of bytes specified by the Content-Length HTTP header".

Generally, when a request is not sent with a 'Content-Length' header, it is usually because the request is sent as a chunked request. In a chunked request, the 'Content-Length' header is replaced with the 'Transfer-Encoding: chunked' header.

It appeared from the error that S3 wasn't able to handle the chunked request sent by Excon which is used by asset_sync gem internally. I did some digging and found out that Excon luckily provides a way to disable sending chunked requests. This can easily be done by setting 'nonblock' property to false. I added the following to my initializers:

  if  ENV["RAILS_GROUPS"] == 'assets'
  Excon.defaults[:nonblock] = false
end

And ta-da assets started uploading properly.

I hope this helps someone who is struggling to upload large assets using asset_sync gem and getting a 400 Bad Request error with an "IncompleteBody" message.