A large upload to S3 dies mid-transfer. The parts that already made it up don’t just vanish — they keep sitting there, billed every month, invisible to the console and to aws s3 ls.

Hi everyone 👋

When an application uploads a large file to S3 using multipart upload and the connection drops partway through, the obvious assumption is: the upload failed, nothing happened, no harm done. That assumption is wrong in a way that quietly costs money.

😱 The uncomfortable truth

The chunks of data that did make it to S3 before the connection dropped don’t get cleaned up automatically. They stay on S3’s infrastructure as an incomplete multipart upload, and AWS keeps billing storage for those parts every month — indefinitely, until something explicitly tells S3 to get rid of them.

🔍 The part that makes this actually painful: you can’t see it

This isn’t just an easy-to-miss cost — it’s a genuinely invisible one. Incomplete multipart upload parts don’t show up in the S3 Console’s normal object listing, and they don’t show up in a regular aws s3 ls. They live in a separate bookkeeping structure (multipart upload IDs and their parts) that ordinary object listing simply doesn’t surface.

If an application uploads thousands of large files and a meaningful fraction of those uploads fail — flaky client networks, mobile uploads, batch jobs that get killed mid-run — the abandoned parts pile up steadily in the background, and the storage bill grows for data that, as far as any normal tooling shows you, doesn’t exist.

🛠️ The fix

S3 has a purpose-built Lifecycle action for exactly this: AbortIncompleteMultipartUpload.

  • Add a Lifecycle Rule to the bucket with the AbortIncompleteMultipartUpload action, set to trigger after 1–2 days of a multipart upload sitting incomplete.
  • Once that window passes, S3 automatically aborts the upload and deletes the orphaned parts — no need to enumerate or find them manually.
  • Lifecycle Rules themselves have no additional cost, and S3 evaluates them roughly once a day, so this is a “set it once” fix rather than something that needs ongoing attention.

💡 What we learned

  • “It failed, so nothing was saved” is not a safe assumption for multipart uploads — partial success is the whole point of multipart upload’s design (it’s what lets a retry resume instead of restarting from zero), and that same design is exactly what leaves orphaned billed data behind on failure.
  • Not everything that costs money is visible through the tools you normally check. aws s3 ls and the console object listing are the first place anyone looks for “what’s actually on this bucket” — and neither one shows this.
  • This is a “set it once, forget it” fix, which makes it a good candidate for a standard baseline on every bucket that accepts large uploads, rather than something to remember to configure reactively per bucket.

📚 References