esiale
esiale

Reputation: 93

Nodejs AWS S3 createPresignedPost returns error Cannot read properties of undefined (reading 'endsWith')

I have the following code:

const { S3Client } = require('@aws-sdk/client-s3');
const { createPresignedPost } = require('@aws-sdk/s3-presigned-post');

router.post(
  '/sign-s3', async (req, res, next) => {
    const { name, type } = req.body;
    const client = new S3Client({
      region: 'eu-central-1',
      credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
      },
    });
    const params = {
      Bucket: process.env.S3_BUCKET_NAME,
      Expires: 60,
      Conditions: [
        ['content-length-range', 100, 5242880],
        { 'Content-Type': 'image/jpeg' },
      ],
      Fields: {
        key: `blog/${name}`,
        'Content-Type': type,
        success_action_status: '201',
      },
    };
    try {
      const data = await createPresignedPost(client, params);
      return res.json(data);
    } catch (err) {
      return next({ status: 500, message: err.message });
    }
  }
);

This route returns the following error:

Cannot read properties of undefined (reading 'endsWith')

This error is not very helpful. I tried passing credentials directly into the S3Client object configuration because I had issues with V2 SDK not reading the credentials from .env automatically (the docs claim it should) but that didn't help. I ran these params with V2 and it worked just fine so I'm sure they're not the problem here. Any ideas?

Upvotes: 3

Views: 2100

Answers (1)

esiale
esiale

Reputation: 93

I've figured it out so I'm going to answer my own question in case anyone Googles this.

The problem was that I passed key inside Fields. Doing so is fine for AWS js SDK v2 but not so for AWS js SDK v3. Where v3 createPresignedPost expects Key to be passed directly, like so:

const params = {
    Bucket: process.env.S3_BUCKET_NAME,
    Expires: 60,
    Conditions: [
        ['content-length-range', 100, 5242880],
        { 'Content-Type': 'image/jpeg' },
    ],
    Fields: {
        'Content-Type': type,
        success_action_status: '201',
    },
    Key: '${name}',
};

I did try passing only Bucket to createPresignedPost while trying out different approaches. Apparently, you don't get a proper error if you don't include Key and it's required.

Upvotes: 6

Related Questions