aws-sdk-js-v3 icon indicating copy to clipboard operation
aws-sdk-js-v3 copied to clipboard

Misleading error message - Cannot read property 'byteLength' of undefined

Open ameotoko opened this issue 4 years ago • 6 comments

Describe the bug

The exception Cannot read property 'byteLength' of undefined is thrown by a client instance in many cases, but, as pointed out in https://github.com/aws/aws-sdk-js-v3/issues/2411#issuecomment-864127937, the problem might be, that keys in the credentials object are spelled in PascalCase, instead of camelCase.

I just had the same problem, and this was indeed what caused it. What makes it worse is the fact, that in the SDK Reference, lower-case properties marked as readonly, so you would never think to dig in that direction.

Your environment

SDK version number

@aws-sdk/client-s3@v3, @aws-sdk/lib-storage@v3

Is the issue in the browser/Node.js/ReactNative?

Browser

ameotoko avatar Oct 13 '21 21:10 ameotoko

Thanks for bringing this up, a better error message should be populated. Will take it to the team to decide the priority for this.

ajredniwja avatar Nov 22 '21 19:11 ajredniwja

I am seeing the same error, despite having all keys in camelCase

import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";

const awsConfiguration = {
  region: "us-east-1",
  credentials: {
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  },
};

const dynamodbClient = new DynamoDBClient(awsConfiguration);

michaelclark2 avatar Feb 08 '22 17:02 michaelclark2

I'm having this exact same issue with an IAMClient and errors with the following code snippet:

iam = new iamc.IAMClient({
            region: region,
            credentials: {
                accessKeyId: client_params.AccessKeyId,
                secretAccessKey: client_params.SecretAccessKey,
                sessionToken: client_params.SessionToken
            }
        })

drmmarsunited avatar Jun 21 '22 22:06 drmmarsunited

Same issue, regardless of if PascalCase or camelCase notation is used.

const credentials = {
    SessionToken: process.env.AWS_SESSION_TOKEN
  }

  const client = new CloudFormationClient({
    credentials,
    region: 'us-east-2',
  });

evanottinger avatar Jul 25 '22 18:07 evanottinger

+1 here :(

I've tested this using full admin credentials and also temp credentials scoped to 1 single bucket, either way I always get the same error:

/application/node_modules/@aws-sdk/util-buffer-from/dist-cjs/index.js:6
const fromArrayBuffer = (input, offset = 0, length = input.byteLength - offset) => {
                                                           ^

TypeError: Cannot read properties of undefined (reading 'byteLength')
    at fromArrayBuffer (/application/node_modules/@aws-sdk/util-buffer-from/dist-cjs/index.js:6:60)
    at castSourceData (/application/node_modules/@aws-sdk/hash-node/dist-cjs/index.js:29:51)
    at Hash.update (/application/node_modules/@aws-sdk/hash-node/dist-cjs/index.js:12:26)
    at hmac (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/credentialDerivation.js:36:10)
    at getSigningKey (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/credentialDerivation.js:11:29)
    at SignatureV4.getSigningKey (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/SignatureV4.js:153:57)
    at SignatureV4.signRequest (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/SignatureV4.js:98:73)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async /application/node_modules/@aws-sdk/middleware-signing/dist-cjs/middleware.js:13:18
    at async StandardRetryStrategy.retry (/application/node_modules/@aws-sdk/middleware-retry/dist-cjs/StandardRetryStrategy.js:51:46) {
  '$metadata': { attempts: 1, totalRetryDelay: 0 }
}

this is my code:

import { S3Client, S3ClientConfig, ListObjectsCommand, ListObjectsCommandInput } from '@aws-sdk/client-s3'

...
    private s3Client: S3Client;

    constructor(accessKey: string, secretAccessKey: string) {
        this.config = {
            region: "ap-southeast-2",
            credentials: {
                accessKeyId: accessKey,
                secretAccessKey: secretAccessKey
            }
        }

        this.s3Client = new S3Client(this.config);
    }


      public async getS3Objects(bucketName: string) {
          const params: ListObjectsCommandInput = {
              Bucket: 'my-bucket'
          };

           const command = new ListObjectsCommand(params);

           return await this.s3Client.send(command);
      }

My bucket has the following settings:

  • Name: my-bucket
  • Region: Asia Pacific (Sydney) ap-southeast-2
  • Access: Bucket and objects not public. // Tried also making all the objects public, and got same result :/
  • Versioning: Disabled
  • Encryption: Amazon S3-managed keys (SSE-S3)

Not sure if this is useful, but this is the config object I get when logging on the console after I created the S3Client instance:

this.s3Client {
  apiVersion: '2006-03-01',
  disableHostPrefix: false,
  logger: {},
  regionInfoProvider: [AsyncFunction: defaultRegionInfoProvider],
  serviceId: 'S3',
  signerConstructor: [class SignatureV4MultiRegion],
  signingEscapePath: false,
  urlParser: [Function: parseUrl],
  useArnRegion: [AsyncFunction (anonymous)],
  region: [AsyncFunction: region],
  credentials: [Function (anonymous)],
  runtime: 'node',
  defaultsMode: [AsyncFunction (anonymous)],
  base64Decoder: [Function: fromBase64],
  base64Encoder: [Function: toBase64],
  bodyLengthChecker: [Function: calculateBodyLength],
  credentialDefaultProvider: [Function (anonymous)],
  defaultUserAgentProvider: [AsyncFunction (anonymous)],
  eventStreamSerdeProvider: [Function: eventStreamSerdeProvider],
  getAwsChunkedEncodingStream: [Function: getAwsChunkedEncodingStream],
  maxAttempts: [AsyncFunction (anonymous)],
  md5: [Function: bound Hash],
  requestHandler: NodeHttpHandler {
    metadata: { handlerProtocol: 'http/1.1' },
    configProvider: Promise { <pending> }
  },
  retryMode: [AsyncFunction (anonymous)],
  sha1: [Function: bound Hash],
  sha256: [Function: bound Hash],
  streamCollector: [Function: streamCollector],
  streamHasher: [Function: readableStreamHasher],
  useDualstackEndpoint: [AsyncFunction (anonymous)],
  useFipsEndpoint: [AsyncFunction: useFipsEndpoint],
  utf8Decoder: [Function: fromUtf8],
  utf8Encoder: [Function: toUtf8],
  tls: true,
  endpoint: [Function (anonymous)],
  isCustomEndpoint: false,
  retryStrategy: [AsyncFunction: retryStrategy],
  systemClockOffset: 0,
  signer: [Function: signer],
  bucketEndpoint: false,
  forcePathStyle: false,
  useAccelerateEndpoint: false,
  disableMultiregionAccessPoints: [Function (anonymous)],
  customUserAgent: undefined,
  eventStreamMarshaller: EventStreamMarshaller {
    universalMarshaller: EventStreamMarshaller {
      eventStreamCodec: [EventStreamCodec],
      utfEncoder: [Function: toUtf8]
    }
  }
}

the command:

command:  ListObjectsCommand {
  middlewareStack: {
    add: [Function: add],
    addRelativeTo: [Function: addRelativeTo],
    clone: [Function: clone],
    use: [Function: use],
    remove: [Function: remove],
    removeByTag: [Function: removeByTag],
    concat: [Function: concat],
    applyToStack: [Function: cloneTo],
    resolve: [Function: resolve]
  },
  input: { Bucket: 'my-bucket' }
}

swiser-gus avatar Aug 03 '22 00:08 swiser-gus

+1 here :(

I've tested this using full admin credentials and also temp credentials scoped to 1 single bucket, either way I always get the same error:

/application/node_modules/@aws-sdk/util-buffer-from/dist-cjs/index.js:6
const fromArrayBuffer = (input, offset = 0, length = input.byteLength - offset) => {
                                                           ^

TypeError: Cannot read properties of undefined (reading 'byteLength')
    at fromArrayBuffer (/application/node_modules/@aws-sdk/util-buffer-from/dist-cjs/index.js:6:60)
    at castSourceData (/application/node_modules/@aws-sdk/hash-node/dist-cjs/index.js:29:51)
    at Hash.update (/application/node_modules/@aws-sdk/hash-node/dist-cjs/index.js:12:26)
    at hmac (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/credentialDerivation.js:36:10)
    at getSigningKey (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/credentialDerivation.js:11:29)
    at SignatureV4.getSigningKey (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/SignatureV4.js:153:57)
    at SignatureV4.signRequest (/application/node_modules/@aws-sdk/signature-v4/dist-cjs/SignatureV4.js:98:73)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async /application/node_modules/@aws-sdk/middleware-signing/dist-cjs/middleware.js:13:18
    at async StandardRetryStrategy.retry (/application/node_modules/@aws-sdk/middleware-retry/dist-cjs/StandardRetryStrategy.js:51:46) {
  '$metadata': { attempts: 1, totalRetryDelay: 0 }
}

this is my code:

import { S3Client, S3ClientConfig, ListObjectsCommand, ListObjectsCommandInput } from '@aws-sdk/client-s3'

...
    private s3Client: S3Client;

    constructor(accessKey: string, secretAccessKey: string) {
        this.config = {
            region: "ap-southeast-2",
            credentials: {
                accessKeyId: accessKey,
                secretAccessKey: secretAccessKey
            }
        }

        this.s3Client = new S3Client(this.config);
    }


      public async getS3Objects(bucketName: string) {
          const params: ListObjectsCommandInput = {
              Bucket: 'my-bucket'
          };

           const command = new ListObjectsCommand(params);

           return await this.s3Client.send(command);
      }

My bucket has the following settings:

  • Name: my-bucket
  • Region: Asia Pacific (Sydney) ap-southeast-2
  • Access: Bucket and objects not public. // Tried also making all the objects public, and got same result :/
  • Versioning: Disabled
  • Encryption: Amazon S3-managed keys (SSE-S3)

Not sure if this is useful, but this is the config object I get when logging on the console after I created the S3Client instance:

this.s3Client {
  apiVersion: '2006-03-01',
  disableHostPrefix: false,
  logger: {},
  regionInfoProvider: [AsyncFunction: defaultRegionInfoProvider],
  serviceId: 'S3',
  signerConstructor: [class SignatureV4MultiRegion],
  signingEscapePath: false,
  urlParser: [Function: parseUrl],
  useArnRegion: [AsyncFunction (anonymous)],
  region: [AsyncFunction: region],
  credentials: [Function (anonymous)],
  runtime: 'node',
  defaultsMode: [AsyncFunction (anonymous)],
  base64Decoder: [Function: fromBase64],
  base64Encoder: [Function: toBase64],
  bodyLengthChecker: [Function: calculateBodyLength],
  credentialDefaultProvider: [Function (anonymous)],
  defaultUserAgentProvider: [AsyncFunction (anonymous)],
  eventStreamSerdeProvider: [Function: eventStreamSerdeProvider],
  getAwsChunkedEncodingStream: [Function: getAwsChunkedEncodingStream],
  maxAttempts: [AsyncFunction (anonymous)],
  md5: [Function: bound Hash],
  requestHandler: NodeHttpHandler {
    metadata: { handlerProtocol: 'http/1.1' },
    configProvider: Promise { <pending> }
  },
  retryMode: [AsyncFunction (anonymous)],
  sha1: [Function: bound Hash],
  sha256: [Function: bound Hash],
  streamCollector: [Function: streamCollector],
  streamHasher: [Function: readableStreamHasher],
  useDualstackEndpoint: [AsyncFunction (anonymous)],
  useFipsEndpoint: [AsyncFunction: useFipsEndpoint],
  utf8Decoder: [Function: fromUtf8],
  utf8Encoder: [Function: toUtf8],
  tls: true,
  endpoint: [Function (anonymous)],
  isCustomEndpoint: false,
  retryStrategy: [AsyncFunction: retryStrategy],
  systemClockOffset: 0,
  signer: [Function: signer],
  bucketEndpoint: false,
  forcePathStyle: false,
  useAccelerateEndpoint: false,
  disableMultiregionAccessPoints: [Function (anonymous)],
  customUserAgent: undefined,
  eventStreamMarshaller: EventStreamMarshaller {
    universalMarshaller: EventStreamMarshaller {
      eventStreamCodec: [EventStreamCodec],
      utfEncoder: [Function: toUtf8]
    }
  }
}

the command:

command:  ListObjectsCommand {
  middlewareStack: {
    add: [Function: add],
    addRelativeTo: [Function: addRelativeTo],
    clone: [Function: clone],
    use: [Function: use],
    remove: [Function: remove],
    removeByTag: [Function: removeByTag],
    concat: [Function: concat],
    applyToStack: [Function: cloneTo],
    resolve: [Function: resolve]
  },
  input: { Bucket: 'my-bucket' }
}

I actually made it work, by adding the sessionToken as part of the config:

constructor(accessKey: string, secretAccessKey: string, sessionToken: string) {
        this.config = {
            region: "ap-southeast-2",
            credentials: {
                accessKeyId: accessKey,
                secretAccessKey: secretAccessKey,
                sessionToken: sessionToken
            }
        }

        this.s3Client = new S3Client(this.config);
    }

Note: The credentials + sessionToken that I'm passing here are temp credentials I've got from calling the command: GetCredentialsForIdentityCommand

Hope this helps someone else :)

swiser-gus avatar Aug 03 '22 00:08 swiser-gus

Removing the needs-review because we know it requires a better error message. But it's not blocking customer from making request to AWS services. We will implement a fix soon.

AllanZhengYP avatar Aug 15 '22 20:08 AllanZhengYP

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.

github-actions[bot] avatar Sep 15 '22 00:09 github-actions[bot]