fix(upload): fail fast on 0-byte files in multipartUpload

A 0-byte file produced a multipart upload with zero parts, which S3/R2 reject
with a cryptic CompleteMultipartUpload error. Guard file.size === 0 up front
with a clear message, before any S3 request is issued. Cloudflare-upload #4.

Test: tests/multipart-empty-file-guard.test.mjs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-16 20:15:17 -04:00
1 parent 6b603cc21c
commit 04ae0ec4e6
2 files changed
+43

No files matched your search

+5
View File
@@ -177,6 +177,11 @@ export async function multipartUpload({
if (!file) {
throw new Error("File is required");
}
// A 0-byte file produces a multipart upload with zero parts, which S3/R2
// rejects with a cryptic CompleteMultipartUpload error. Fail fast and clearly.
if (typeof file.size === "number" && file.size === 0) {
throw new Error("File is empty (0 bytes). Choose a non-empty file to upload.");
}
const {
CreateMultipartUploadCommand,
+38
View File
@@ -0,0 +1,38 @@
// Scenario (SCN-upload-empty-file):
// Given a 0-byte file,
// When multipartUpload is called,
// Then it rejects FAST with a clear "empty" message and never issues any S3
// request (the old behavior completed a multipart upload with zero parts and
// surfaced a cryptic CompleteMultipartUpload error — Cloudflare-upload #4).
// Disable the network import of the AWS SDK before importing the module.
globalThis.__BITVID_DISABLE_NETWORK_IMPORTS__ = true;
import test from "node:test";
import assert from "node:assert/strict";
const { multipartUpload } = await import("../js/storage/s3-multipart.js");
test("rejects a 0-byte file before any S3 request", async () => {
let sendCalled = false;
const s3 = {
send: async () => {
sendCalled = true;
return {};
},
};
await assert.rejects(
() =>
multipartUpload({
s3,
bucket: "bucket",
key: "u/npub/ns/empty.mp4",
file: { size: 0, type: "video/mp4" },
}),
/empty|0 bytes/i,
"empty file should produce a clear error",
);
assert.equal(sendCalled, false, "must not start a multipart upload for an empty file");
});