1

@TBA gave the solution.
The root cause is not by runtime. It came from SDK v3.
Point: Do not update the code with mixed things (like both of runtime & SDK version together )

Thanks again, TBA.


I was using Node.js 14.x version runtime Lambda to read some json file from S3.

Brief code is below

const AWS = require("aws-sdk");
const s3 = new AWS.S3();

exports.handler = (event) => {
    const { bucketName, objKey } = event
    const params = {
        Bucket: bucketName, 
        Key: objKey
    };
    return new Promise((resolve) => {
        s3.getObject(params, async (err, data) =>{
            if (err) console.log(err, err.stack); 
            else     {
                const contents = JSON.parse(data.Body)
                resolve(contents);
            }
        });
    })
};

and it returned the json data as I expected.

And today I tried to create a new lambda with runtime Node.js 18.x but it returned null or some errors...

Q) Could you give me some advice to solve this ?

+) I used same json file for each lambda
+) Not sure why, but in my case, data.Body.toString() didn't work (I saw some answers in stackoverflow provide that and tried but no lucks)

Thanks in advance!

Case A (returns null)

import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
const s3Client = new S3Client({ region: "ap-northeast-2" });

export const handler = (event) => {
    const { objKey, bucketName } = event;
    const params={
        Bucket: bucketName, 
        Key: objKey
    };
    
    const getObjCommand = new GetObjectCommand(params);
    
    return new Promise((resolve) => {
        s3Client.send(getObjCommand, async (err, data) =>{
            if (err) console.log(err, err.stack); 
            else     {
                const list = JSON.parse(data.Body)
                resolve(list);
            }
        });
    })
};

Case B (returns "Unexpected token o in JSON at position 1")

export const handler = async (event) => {
    const { objKey, bucketName } = event;
    const params={
        Bucket: bucketName, 
        Key: objKey
    };
    
    const getObjCommand = new GetObjectCommand(params);
    const response = await s3Client.send(getObjCommand)
    
    console.log("JSON.parse(response.Body)", JSON.parse(response.Body))
};

Case C (returns "TypeError: Converting circular structure to JSON")

export const handler = async (event) => {
    const { objKey, bucketName } = event;
    const params={
        Bucket: bucketName, 
        Key: objKey
    };
    const getObjCommand = new GetObjectCommand(params);
    
    try {
        const response = await s3Client.send(getObjCommand)
        return JSON.stringify(response.Body)
    } catch(err) {
        console.log("error", err)
        return err
    }
};
Noah Gray
  • 151
  • 1
  • 1
  • 13
  • Could it be that your Lambda function is missing permission to read the object from S3? Can you log the `response.Body` before trying to `JSON.parse` it? – TBA Jan 03 '23 at 07:26
  • @TBA I gave administrator policy to this lambda to check the issue. And when I logged the response.Body, it returns "errorMessage": "Unable to stringify response body" – Noah Gray Jan 03 '23 at 07:44
  • 1
    OK - just wanted to make sure. Note that you're now using v3 of AWS SDK and the `response.Body` is a stream that you first need to transform into a string [(see this thread)](https://stackoverflow.com/a/74699284/3592771) `JSON.parse(await data?.Body?.transformToString())`. – TBA Jan 03 '23 at 08:36
  • Wow, it works now and the thread is very helpful. Thanks a lot @TBA! – Noah Gray Jan 03 '23 at 10:35

1 Answers1

0

GetObjectCommand return you stream "Body", you can't parse directly.

for example

 const response = await s3Client.send(getObjCommand);
 const stream = response.Body;
 return Buffer.concat(await stream.toArray());
Hanoj B
  • 350
  • 2
  • 12