How Deleting package-lock.json Broke AWS S3 Upload Function

namlai
September 03, 2025
3 mins read
How Deleting package-lock.json Broke AWS S3 Upload Function

How Deleting package-lock.json Broke AWS S3 Upload Function

Problem Introduction

In a web project using @aws-sdk/client-s3 (AWS SDK v3), I recently encountered an unexpected error while uploading files from the browser to S3:

The strange part?

This code had worked perfectly fine before. Nothing in the file upload logic had changed. Yet suddenly, the upload crashed at runtime.

aws-s3-upload-broken

Root Cause of the Error

First, I opened the Console tab in the browser’s developer tools and saw the following error

trace-1

TypeError: readableStream.getReader is not a function
    at getAwsChunkedEncodingStream (http://localhost:4300/admin/vendor.7c254d69975f6ea5.js:106506:35)
    at http://localhost:4300/admin/vendor.7c254d69975f6ea5.js:99876:27

But wait, wait, wait! The error came directly from a library? What’s going on here? I needed to dig deeper, so I switched to the Sources tab to check the code in detail.

trace-2

Here is the code in detail. As you can see, this line const reader = readableStream.getReader(); tries to get a reader from readableStream.`

export const getAwsChunkedEncodingStream = (readableStream, options) => {
    const { base64Encoder, bodyLengthChecker, checksumAlgorithmFn, checksumLocationName, streamHasher } = options;
    const checksumRequired = base64Encoder !== undefined &&
        bodyLengthChecker !== undefined &&
        checksumAlgorithmFn !== undefined &&
        checksumLocationName !== undefined &&
        streamHasher !== undefined;
    const digest = checksumRequired ? streamHasher(checksumAlgorithmFn, readableStream) : undefined;
    const reader = readableStream.getReader(); # getReader is undefined
    return new ReadableStream({
        async pull(controller) {
            const { value, done } = await reader.read();
            if (done) {
                controller.enqueue(`0\r\n`);
                if (checksumRequired) {
                    const checksum = base64Encoder(await digest);
                    controller.enqueue(`${checksumLocationName}:${checksum}\r\n`);
                    controller.enqueue(`\r\n`);
                }
                controller.close();
            }
            else {
                controller.enqueue(`${(bodyLengthChecker(value) || 0).toString(16)}\r\n${value}\r\n`);
            }
        },
    });
};

I wondered: which line of code was calling that function? It turned out that the following code was responsible. After adding some console logs to check, I realized that the uploadCommand was triggered by the client.

const client = this.getS3Client(credentials);
const uploadCommand = new PutObjectCommand({
  Bucket: this.bucket,
  Key: fileKey,
  Body: file,
});

return client.send(uploadCommand).then(() => fileKey);

I run npm ls @smithy/util-stream, here are results,

├─┬ @aws-sdk/client-s3@3.844.0
│ ├─┬ @aws-sdk/middleware-flexible-checksums@3.844.0
│ │ └── @smithy/util-stream@4.2.3 deduped
│ ├─┬ @aws-sdk/middleware-sdk-s3@3.844.0
│ │ └── @smithy/util-stream@4.2.3 deduped
│ └── @smithy/util-stream@4.2.3 deduped

Deleting and regenerating package-lock.json led to unintended SDK upgrades. Our package.json contained:

"@aws-sdk/client-s3": "^3.x.x"

So when the package-lock.json file was deleted and re-generated, npm install resolved newer versions that caused problems

How I Solved It

I rolled back to a working package-lock.json. Then, I ran:

rm -rf node_modules/
npm install