Skip to main content

Deleting

4 min read

This page covers del, which deletes one path, a list of paths, or everything under a prefix, and the calls that clean up multipart uploads that were never completed.

All three shapes resolve to Promise<void> and treat "already gone" as success. They differ in how many requests they make and what they throw when storage refuses part of the work.

Anything else is refused with invalid_input. A path with a . or .. segment throws a TypeError; see Paths.

The upload handler also deletes on its own: a throw out of onUploadComplete, or a cancel() from the browser, removes the object that upload wrote. See onUploadComplete.


One path#

One DELETE request. A 404 counts as success, so a delete is safe to run from a retried job or an at-least-once queue consumer. Any other failure throws; see Errors.

del never says whether anything was there. To find out, call bucket.exists(path) first.


An array#

Sent as batch deletes in chunks of 1000 paths, so a 5000-path array is five requests. A bad path fails the chunk it is in; earlier chunks have already run.

When storage reports keys as failed, the SDK re-checks each one and keeps only the paths still there. If any survive, del throws partial_delete with them in failed. Everything not in failed was deleted. To recover, retry with e.failed.

Use BlobError.is(e), never instanceof. See Errors.


A prefix#

Pages through list() at 1000 objects per page and batch-deletes each page as it goes. A prefix with 100,000 objects is 100 list requests and 100 batch deletes, run one after another. It is not atomic; objects written under the prefix while it runs may or may not be caught.

Failures work as for an array. Survivors from every page are collected and thrown as partial_delete.

Warning

del({ prefix: '' }) would match every object in the bucket, so an empty prefix is refused with invalid_input. This protects against an unset variable or an empty form field. To wipe the bucket on purpose, say so:

all is only consulted for the empty prefix.


move leaves a copy on failure#

move is a copy followed by a delete, because storage has no rename. If the copy fails, nothing changed and you get the copy's error. If the copy succeeds and the delete fails, move throws move_left_a_copy and keeps the destination, so you have two objects rather than none. The original error is on cause.


Incomplete multipart uploads#

A multipart upload becomes an object only when it is completed. Until then its parts are billed storage that list() cannot see, and the bucket cannot be deleted while one exists. A browser tab closed mid-upload leaves exactly this behind.

bucket.put() and a browser cancel() abort their own uploads on failure. Anything else needs a sweep. The cron that runs it is on Abandoned uploads; the calls it uses are below.

listMultipartUploads#

Returns every upload started and neither completed nor aborted, paging internally until it has them all. prefix is optional.

FieldMeaning
pathThe key the upload was started for. Nothing is stored there yet.
uploadIdStorage's id for the upload, needed to abort it.
initiatedAtWhen it was started. What "stale" is measured against.

abortMultipartUpload#

Throws the upload away with every part that landed for it. An upload that is already gone counts as success. An empty uploadId is refused with invalid_input.

onUploadComplete receives multipartUploadId for exactly this pair. Store it with your row and you can abort a specific upload later without listing the bucket. It is undefined for a single PUT.

abortStaleMultipartUploads#

List plus abort in one call, meant for a cron. olderThan is required, a Duration. Only uploads started longer ago than that are touched, so a window longer than your slowest upload never aborts one still running. A day is a reasonable default.

Note

An abandoned upload under the multipart threshold is not a multipart upload. It is an ordinary stored object that list() can see, and none of the calls above can find it. See Abandoned uploads.


Error codes#

CodeRaised by
partial_deleteAn array or prefix delete where objects survived. failed lists them.
move_left_a_copymove, when the source delete failed.
invalid_inputA bad DeleteTarget, an empty prefix without all, an empty uploadId.

del never raises not_found. Statuses and extra fields are on Errors.