How to find and abort incomplete multipart uploads in S3

TL;DR

A multipart upload that's interrupted — a dropped connection, a crashed script, a cancelled browser tab — leaves its uploaded parts in the bucket even though the object never appears in a normal listing or ListObjectsV2. Those parts are billed as stored data until something aborts the upload or a lifecycle rule cleans them up. S3 Viewer's Incomplete uploads dialog lists every open multipart upload under the current prefix via ListMultipartUploads and aborts one, several, or all of them with AbortMultipartUpload.

Steps

Step-by-step.

  1. 01

    In S3 Viewer: Incomplete uploads, from the bucket toolbar

    Open the bucket toolbar's overflow menu and choose Incomplete uploads. The dialog lists every open multipart upload under the current prefix — key, when it was started, and how old it is — paginated with a Load more button. Select the ones you want and click Abort selected, or use Abort all listed to clear everything currently shown. Failures are reported per upload rather than failing the whole batch.
  2. 02

    AWS CLI: list them first

    list-multipart-uploads returns every open upload for the bucket (or a prefix, with --prefix), each with its own UploadId — the same key can have more than one open upload if it was retried.
    aws s3api list-multipart-uploads --bucket my-bucket --prefix uploads/
  3. 03

    AWS CLI: abort one, or loop over all of them

    Aborting needs both the key and its UploadId — the key alone isn't enough, since there can be more than one open upload for it. jq turns the listing into arguments for a loop.
    aws s3api abort-multipart-upload \
      --bucket my-bucket --key uploads/video.mp4 --upload-id <id>
    
    # abort everything under a prefix
    aws s3api list-multipart-uploads --bucket my-bucket --prefix uploads/ \
      --query 'Uploads[].[Key,UploadId]' --output text |
    while read -r key upload_id; do
      aws s3api abort-multipart-upload --bucket my-bucket --key "$key" --upload-id "$upload_id"
    done
  4. 04

    Set a lifecycle rule so this doesn't need doing by hand

    A bucket lifecycle rule with an AbortIncompleteMultipartUpload action (commonly set to a few days) cleans these up automatically going forward. That's the right long-term fix; S3 Viewer's dialog and the CLI commands above are for clearing an existing backlog or checking there isn't one.
    {
      "Rules": [{
        "ID": "abort-incomplete-multipart",
        "Status": "Enabled",
        "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 3 }
      }]
    }
  5. 05

    SDK: same two calls, scripted

    ListMultipartUploadsCommand then AbortMultipartUploadCommand per result — this is exactly what S3 Viewer's route does, at bounded concurrency, with NoSuchUpload treated as already-aborted rather than a failure.
    const { Uploads = [] } = await s3.listMultipartUploads({ Bucket, Prefix });
    for (const { Key, UploadId } of Uploads) {
      await s3.abortMultipartUpload({ Bucket, Key, UploadId });
    }
Under the hood

What's actually happening.

A multipart upload exists in a separate namespace from ordinary objects for its entire lifetime. UploadPart stores bytes against an UploadId, but nothing becomes a real, listable object until CompleteMultipartUpload assembles the parts. If that last call never happens — connection dropped, process crashed, upload cancelled — the parts stay exactly where UploadPart put them, billed as storage, with no corresponding key for ListObjectsV2 to ever return.


ListMultipartUploads is the only way to see this hidden namespace: it returns every open upload for the bucket (optionally scoped by prefix), each with its own key and UploadId — the same key can have several open uploads if it was retried without the earlier attempt being cleaned up. AbortMultipartUpload is the only way to remove one, and needs both fields; the key alone can't disambiguate which upload to cancel.


S3 Viewer's route pages through ListMultipartUploads the same way object listing pages through ListObjectsV2, and aborts a selection at bounded concurrency, treating a NoSuchUpload response — the upload was already gone, aborted elsewhere or already completed — as a success rather than a failure. None of this replaces a lifecycle rule for ongoing prevention; it's for seeing what's accumulated and clearing it.

FAQ

Common questions.

Why do I have objects in my bill that don't show up in my bucket?

They're not objects yet — they're parts of multipart uploads that never completed. A CompleteMultipartUpload call is what turns uploaded parts into a real object; without it, the parts sit in storage, billed, but invisible to ListObjectsV2 and the console's normal listing. list-multipart-uploads (or S3 Viewer's Incomplete uploads dialog) is how you find them.

How do I list incomplete multipart uploads in S3?

aws s3api list-multipart-uploads --bucket my-bucket, optionally with --prefix to scope it. Each result includes the Key, the UploadId, when it was initiated, and who started it. S3 Viewer's Incomplete uploads dialog shows the same information, paginated, for the current prefix.

How do I delete an incomplete multipart upload?

You abort it, with both its key and UploadId: aws s3api abort-multipart-upload --bucket my-bucket --key <key> --upload-id <id>. A plain DeleteObject won't touch it, since there's no completed object yet to delete. S3 Viewer's dialog aborts one, several, or every upload currently listed.

Does an incomplete multipart upload cost money?

Yes — every uploaded part is billed as stored data at the normal rate for as long as it sits there, even though no finished object exists. This is exactly why AbortIncompleteMultipartUpload lifecycle rules and cleanup tools like this exist: a backlog of failed uploads can accumulate real storage cost silently.

How do I stop incomplete multipart uploads from piling up automatically?

Add a bucket lifecycle rule with an AbortIncompleteMultipartUpload action and a DaysAfterInitiation value (a few days is typical). S3 then aborts any multipart upload older than that on its own, so failed or abandoned uploads never accumulate indefinitely.

Does this work the same on Cloudflare R2, Backblaze B2 and MinIO?

Yes. ListMultipartUploads and AbortMultipartUpload are both standard S3 API operations, implemented the same way by R2, B2 and MinIO, so S3 Viewer's Incomplete uploads dialog behaves identically on every connected provider.
Use S3 Viewer for this

Skip the CLI. Try it in the browser.

S3 Viewer turns the steps above into a single click. Open source, self-hostable, free.