oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
71.84k stars 2.56k forks source link

@aws-sdk/client-s3 not working with Bun (same code works with Node) #6803

Open alexandernst opened 8 months ago

alexandernst commented 8 months ago

What version of Bun is running?

1.0.7

What platform is your computer?

Darwin 23.0.0 arm64 arm

What steps can reproduce the bug?

Run the following code:

const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3");

const r2 = new S3Client({
  endpoint: `https://<cloudflare account id>.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: "<access key id>",
    secretAccessKey: "<secret access key>",
  },
  region: 'auto',
});

const fileStream = fs.createReadStream("/tmp/test.txt");
await r2.send(
  new PutObjectCommand({
    Bucket: "<bucket name>",
    Key: "test.txt",
    Body: fileStream
  })
);
fileStream.close();

What is the expected behavior?

The file should be uploaded to Cloudflare's R2 (or any other S3-compatible API)

What do you see instead?

1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.decorateServiceException = exports.ServiceException = void 0;
4 | class ServiceException extends Error {
5 |     constructor(options) {
6 |         super(options.message);
            ^
SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your secret access key and signing method. 
      at new ServiceException (/Users/alexandernst/Proyectos/test/node_modules/@smithy/smithy-client/dist-cjs/exceptions.js:6:8)
      at new S3ServiceException (/Users/alexandernst/Proyectos/test/node_modules/@aws-sdk/client-s3/dist-cjs/models/S3ServiceException.js:8:8)
      at throwDefaultError (/Users/alexandernst/Proyectos/test/node_modules/@smithy/smithy-client/dist-cjs/default-error-handler.js:8:21)
      at /Users/alexandernst/Proyectos/test/node_modules/@smithy/smithy-client/dist-cjs/default-error-handler.js:18:8
      at /Users/alexandernst/Proyectos/test/node_modules/@aws-sdk/client-s3/dist-cjs/protocols/Aws_restXml.js:5721:11
      at processTicksAndRejections (:61:76)

Additional information

The same code works fine with Node

chhpt commented 3 months ago

May I ask if there has been any progress here? I have encountered the same issue.

samohovets commented 2 months ago

The same error using Bun 1.1.5. The version of @aws-sdk/client-s3 is 3.509.0.

cjkihl commented 2 months ago

Same issue for me Bun 1.1.4 @aws-sdk/client-s3: 3.565.0

Blankeos commented 1 month ago

My error is always: FailedToOpenSocket: Was there a typo in the url or port?

AlbertSabate commented 3 weeks ago

Hello,

To leave it as feedback, I made it work by adding the following config to the client constructor:

const s3Client = new S3Client({
  endpoint: `xxxx`,
  forcePathStyle: true, // This is what made it work.
  credentials: {
    accessKeyId: 'xxx',
    secretAccessKey: 'xxx',
  },
});

Credits to this solution: https://medium.com/la-mobilery/short-bun-hono-send-and-get-documents-using-aws-s3-client-fff20d0ba80e

My investigation:

  1. The URL that the client generates is incorrect. It adds xxx..r2.cloudflarestorage.com (Note the two dots)
  2. The signature seems to be invalid because the signature was generated with the wrong URL.

The URL gets correctly generated in NodeJS; therefore, the signature is valid. Something is off with BunJS generating this URL, the signature seems to work properly as with forcePathStyle: true works. I hope I have helped narrow down the issue.

olsn commented 1 week ago

What worked for me, was to use: @aws-sdk/lib-storage instead of a manual PutObject-Command. I am using a third-party-s3-provider, and not AWS.

import { Upload } from "@aws-sdk/lib-storage";

//....

const fileStream = createReadStream(localFilePath);
    const upload = new Upload({
      client: this.client,
      params: {
        Bucket: bucket,
        Key: key,
        Body: fileStream,
        Metadata: {
          ....
        },
      },
    });
    try {
      await upload.done();
    } catch (e) {
      console.error("Error uploading file to S3", e);
      throw e;
    }

There was also no need for the forcePathStyle: true-setting.

Got the reference-implementation over at multer-s3