Skip to content

Upload class #7382

@etcart

Description

@etcart

Checkboxes for prior research

Describe the bug

version 3.896+
Upload class, when given a stream (i.e. from fs.createReadStream) which is larger than the partSize (5MB)
"fails" after uploading

{"level":"info","message":"{\n  loaded: 5242880,\n  total: 0,\n  part: 1,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:23:59.432Z"}
{"level":"info","message":"{\n  loaded: 10485760,\n  total: 0,\n  part: 2,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:23:59.433Z"}
{"level":"info","message":"{\n  loaded: 15728640,\n  total: 0,\n  part: 3,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:23:59.606Z"}
{"level":"info","message":"{\n  loaded: 20971520,\n  total: 0,\n  part: 4,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:23:59.812Z"}
{"level":"info","message":"{\n  loaded: 26214400,\n  total: 0,\n  part: 5,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:23:59.847Z"}
{"level":"info","message":"{\n  loaded: 31457280,\n  total: 0,\n  part: 6,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:23:59.977Z"}
{"level":"info","message":"{\n  loaded: 36700160,\n  total: 0,\n  part: 7,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:00.157Z"}
{"level":"info","message":"{\n  loaded: 41943040,\n  total: 0,\n  part: 8,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:00.326Z"}
{"level":"info","message":"{\n  loaded: 47185920,\n  total: 0,\n  part: 9,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:00.496Z"}
{"level":"info","message":"{\n  loaded: 52428800,\n  total: 0,\n  part: 10,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:00.675Z"}
{"level":"info","message":"{\n  loaded: 57671680,\n  total: 0,\n  part: 11,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:00.907Z"}
{"level":"info","message":"{\n  loaded: 62914560,\n  total: 0,\n  part: 12,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:01.130Z"}
{"level":"info","message":"{\n  loaded: 68157440,\n  total: 0,\n  part: 13,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:01.322Z"}
{"level":"info","message":"{\n  loaded: 69206016,\n  total: 0,\n  part: 16,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:02.802Z"}
{"level":"info","message":"{\n  loaded: 74448896,\n  total: 0,\n  part: 14,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:03.271Z"}
{"level":"info","message":"{\n  loaded: 79691776,\n  total: 0,\n  part: 15,\n  Key: 'source-key-e89738',\n  Bucket: 'source-bucket-4e310c'\n}","sender":"aws-client/s3","timestamp":"2025-09-26T23:24:03.290Z"}

...<test output>...

  Error {
    message: 'Expected 0 part(s) but uploaded 16 part(s).',
  }

this appears to successfully upload, but then fails on validation.
a check of values in the constructor shows that

this.totalBytes = byteLength(this.params.Body) // 0 (lib-storage/src/Upload.ts LN 92)
this.partSize = Math.max(Upload.MIN_PART_SIZE, Math.floor((this.totalBytes || 0) / this.MAX_PARTS)); // 0 (lib-storage/src/Upload.ts LN 96)

checking version < 3.895 and 3.894, the functionality operates without throwing an error, but a check of the value in "this.totalBytes" shows that is also 0, there's just no validation happening to "cause problems" because of this value. it does in any of the tested versions throwing errors or not, cause the total value in that above log example, to be 0

Regression Issue

  • Select this option if this issue appears to be a regression.

SDK version number

@aws-sdk/[email protected]+

Which JavaScript Runtime is this issue in?

Node.js

Details of the browser/Node.js/ReactNative version

v20.12.2

Reproduction Steps

const { Upload } = require('@aws-sdk/lib-storage');
const {
  S3Client,
  CreateBucketCommand,
  DeleteBucketCommand,
  DeleteObjectCommand,
  waitUntilObjectNotExists
} = require("@aws-sdk/client-s3");
const { v4: uuidv4 } = require('uuid');
const fs = require('fs');

const Bucket = 'deleteme' + uuidv4();

const MB = 1024*1024;
const size = 6*MB // (or larger)
const readStream = fs.createReadStream('/dev/urandom', { end: size - 1 });
const s3 = new S3Client({});

await s3.send(new CreateBucketCommand({Bucket}));

const parallelUploads = new Upload({
  params: {
    Bucket,
    Key: "deleteme",
    Body: readStream,
  },
  client: s3
});


const result = await parallelUploads.done() //this should actually throw on 3.896+

await s3.send(new DeleteObjectCommand({ Bucket, Key: "deleteme" }))
await s3.send(new DeleteBucketCommand({ Bucket }))

Observed Behavior

Uncaught Error: Expected 0 part(s) but uploaded 2 part(s).
    at _Upload.__doMultipartUpload (/Users/ecarton/cumulus/packages/aws-client/node_modules/@aws-sdk/lib-storage/dist-cjs/index.js:434:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async _Upload.done (/Users/ecarton/cumulus/packages/aws-client/node_modules/@aws-sdk/lib-storage/dist-cjs/index.js:235:12)

Expected Behavior

upload completes without issue

Possible Solution

No response

Additional Information/Context

No response

Metadata

Metadata

Assignees

Labels

bugThis issue is a bug.closed-for-stalenessp2This is a standard priority issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions