aws / aws-sdk-js-v3

Modularized AWS SDK for JavaScript.
Apache License 2.0
3.05k stars 573 forks source link

@aws-sdk/client-s3 S3Client and ListBucketsCommand results in runtime error "TypeError: core_1.AwsSdkSigV4Signer is not a constructor" #5751

Closed jfunke-well closed 7 months ago

jfunke-well commented 7 months ago

Checkboxes for prior research

Describe the bug

Attempting to list buckets with S3 Client results in a runtime error: "TypeError: core_1.AwsSdkSigV4Signer is not a constructor"

I am building a NestJS application with the S3 Client, instantiating the client at the module level as a singleton, then using that client to list buckets in my application code.

SDK version number

@aws-sdk/client-s3@3.503.1

Which JavaScript Runtime is this issue in?

Node.js

Details of the browser/Node.js/ReactNative version

v20.10.0

Reproduction Steps

Module definition:

import { Module, Logger } from '@nestjs/common';
import { S3Client } from '@aws-sdk/client-s3';
import { S3Service } from './s3.service';

@Module({
  providers: [
    {
      provide: 'S3_CLIENT',
      useFactory: async () => {
        return new S3Client({
          region: 'us-east-1',
        });
      },
    },
    S3Service,
    Logger,
  ],
  exports: ['S3_CLIENT', S3Service],
})
export class S3Module {}

Service implementation

import { Injectable, Inject, Logger } from '@nestjs/common';
import { S3Client, GetObjectCommand, PutObjectCommand, ListBucketsCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

@Injectable()
export class S3Service {
  constructor(
    @Inject('S3_CLIENT') private s3Client: S3Client,
    private logger: Logger
  ) {}

  private async getPresignedUrlFromS3(command: GetObjectCommand | PutObjectCommand, errorLog: string): Promise<string | undefined> {
    console.log('S3 CLIENT', this.s3Client);
    // logs confirm that the s3client exists and is not undefined...

    const listCommand = new ListBucketsCommand({});

    console.log('LISTING BUCKETS');
    try {
      const { Owner, Buckets } = await this.s3Client.send(listCommand);
      console.log(`${Owner?.DisplayName} owns ${Buckets?.length} bucket${Buckets?.length === 1 ? '' : 's'}:`);
      console.log(`${Buckets?.map((b) => ` • ${b.Name}`).join('\n')}`);
    } catch (err) {
      console.error(err);
    }

    try {
      const signedUrl = getSignedUrl(this.s3Client, command, { expiresIn: 3600 }); // URL will be valid for 1 hour
      return signedUrl;
    } catch (error) {
      console.log('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%', error);
      this.logger.error(error, errorLog);
      return undefined;
    }
  }

  async getSignedUrlUpload({ bucket, key }: { bucket: string; key: string }): Promise<string | undefined> {
    const command = new PutObjectCommand({ Bucket: bucket, Key: key });
    return this.getPresignedUrlFromS3(command, 'Failed to generate upload S3 URL');
  }

  async getSignedUrlDownload({ bucket, key }: { bucket: string; key: string }): Promise<string | undefined> {
    const command = new GetObjectCommand({ Bucket: bucket, Key: key });
    return this.getPresignedUrlFromS3(command, 'Failed to generate download S3 URL');
  }
}

Calling the function results in an error below

Observed Behavior

I receive the runtime error:

TypeError: core_1.AwsSdkSigV4Signer is not a constructor
    at getRuntimeConfig (/service/node_modules/@aws-sdk/client-sts/dist-cjs/runtimeConfig.shared.js:25:25)
    at getRuntimeConfig (/service/node_modules/@aws-sdk/client-sts/dist-cjs/runtimeConfig.js:25:76)
    at new STSClient (/service/node_modules/@aws-sdk/client-sts/dist-cjs/STSClient.js:21:64)
    at /service/node_modules/@aws-sdk/client-sts/dist-cjs/index.js:1535:19
    at /service/node_modules/@aws-sdk/credential-provider-web-identity/dist-cjs/fromWebToken.js:13:12
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at /service/node_modules/@smithy/property-provider/dist-cjs/index.js:79:27
    at coalesceProvider (/service/node_modules/@smithy/property-provider/dist-cjs/index.js:106:18)
    at /service/node_modules/@smithy/property-provider/dist-cjs/index.js:124:18
    at _SignatureV4S3Express.credentialProvider (/service/node_modules/@smithy/signature-v4/dist-cjs/index.js:364:25)
    at _SignatureV4S3Express.signRequest (/service/node_modules/@smithy/signature-v4/dist-cjs/index.js:364:25)

Expected Behavior

I should see the S3 buckets logged, or a descriptive error that helps me diagnose what the issue may be

Possible Solution

No response

Additional Information/Context

No response

kuhe commented 7 months ago

Do you have any cyclic dependencies in your application? I recall that this is one of the errors that cycle build problems manifest as.

Secondly, can you confirm your version of @aws-sdk/core? It is a transitive dependency brought in by the @aws-sdk/client-s3 package and it should have an export called AwsSdkSigV4Signer.

jfunke-well commented 7 months ago

Hi @kuhe -

I can try simplifying my application to only import the s3 client in one place, I will give that a shot.

My yarn.lock has two @aws-sdk/core versions are as follows:

"@aws-sdk/core@3.495.0":
  version "3.495.0"
  resolved "https://registry.npmjs.org/@aws-sdk/core/-/core-3.495.0.tgz"
  integrity sha512-TI/jq1cSUR+r1prJ9xXtxMO0u2/jXrWjf3Z2ekForsCObPtR9qkJCYyezargupoSJqZA60KUpOhxrKW/dFJ1rw==
  dependencies:
    "@smithy/core" "^1.3.0"
    "@smithy/protocol-http" "^3.1.0"
    "@smithy/signature-v4" "^2.1.0"
    "@smithy/smithy-client" "^2.3.0"
    "@smithy/types" "^2.9.0"
    tslib "^2.5.0"

"@aws-sdk/core@3.496.0":
  version "3.496.0"
  resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.496.0.tgz#ec1394753b6b2f6e38aea593e30b2db5c7390969"
  integrity sha512-yT+ug7Cw/3eJi7x2es0+46x12+cIJm5Xv+GPWsrTFD1TKgqO/VPEgfDtHFagDNbFmjNQA65Ygc/kEdIX9ICX/A==
  dependencies:
    "@smithy/core" "^1.3.1"
    "@smithy/protocol-http" "^3.1.1"
    "@smithy/signature-v4" "^2.1.1"
    "@smithy/smithy-client" "^2.3.1"
    "@smithy/types" "^2.9.1"
    tslib "^2.5.0"

the @aws-sdk/client-s3 has listed dependency "@aws-sdk/core" "3.496.0"

I will also note - I am trying to use IAM permissions to obtain AWS credentials on the environment where I am seeing this issue.

RanVaknin commented 7 months ago

Hi @jfunke-well ,

You should not have multiple copies in different versions of the same dependency. My advice would be to let yarn resolve the dependency tree for you. You can do that by:

I will also note - I am trying to use IAM permissions to obtain AWS credentials, running this locally since I have no permissions I receive: "CredentialsProviderError: Could not load credentials from any providers - this may or may not help.

This is a different error altogether. This error indicated that your application is not setup with any method of obtaining credentials therefore all of the providers in the credential chain are failing, thus returning this error.

Without understanding how you are setting your credentials it will be challenging to offer advice.

Thanks, Ran~

jfunke-well commented 7 months ago

Hi @RanVaknin apologies for the confusion - I've updated my response to clarify this is happening when deployed on an AWS EKS environment that should be using IAM roles for credentials.

It seems like it was due to conflicting AWS SDK versions in the yarn lock, cleaned up my yarn lock and node_modules and i am now getting the signed url.

Will mark this as closed - thank you for your help

github-actions[bot] commented 7 months ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.