0

Been debugging an entire day and still can't figure out why my s3.upload() method is not being called inside my lambda function. Someone please help

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

exports.handler = (event, context, callback) => {


        var message_body = JSON.parse(event.body);

        let encodedImage = message_body.base64;
        let decodedImage = Buffer.from(encodedImage, 'base64');

        var params = {
            "Body": decodedImage,
            "Bucket": "testbucket1-bucket",
            "Key": "testkey1.jpg"  
        };

        console.log("function triggered. ");


        s3.upload(params).promise()
      .then(data => {
        console.log('complete:PUT Object',data);
         callback(null, data);
      })
      .catch(err => {
        console.log('failure:PUT Object', err);
         callback(err);
      });

};

In Cloudwatch, there are no errors in the entire function. I've made sure the function has access to s3, the bucket is public, and the bucket name is correct numerous times. It just times out after 30 seconds. Neither of the s3.upload() callback methods are being fired and I can't for the life of me figure out why.

Issue Identified

....I just figured out the problem after wasting so much time. My Lambda function had a VPC that didn't grant access to S3.... Now the function is not timing out, and the upload finally is working.

6
  • First of all do you know that S3.upload() function will be called and event loop doesn't wait for its completion and goes directly to userData['event_photo'] = 'FUNCTION TRIGGERED'; And you are also saying that S3.upload() doesn't says Upload Failed nor Upload worked ? Commented Jan 7, 2020 at 4:41
  • yeah doesn't say either Commented Jan 7, 2020 at 5:14
  • how are you triggering this lambda? Commented Jan 7, 2020 at 5:30
  • through api gateway Commented Jan 7, 2020 at 5:33
  • Your lambda works perfectly fine for me. Commented Jan 7, 2020 at 6:01

2 Answers 2

1

the lambda works perfectly fine for me.

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

exports.handler = async (event) => {
    // TODO implement
    var userData = {};

    console.log('1')
    return new Promise((resolve, reject) => {

        console.log('2 type of body: ', typeof event.body);
        const body = JSON.parse(event.body)
        console.log('2.1 body.base64: ', body.base64);

        let decodedImage = Buffer.from(body.base64, 'base64');
        var params = {
            "Body": decodedImage,
            "Bucket": "stackoverflow-help",
            "Key": "testkey1.jpg"  
        };

        console.log('3')

        s3.upload(params, function(err, data){
            console.log('4')

           if(err){
               console.log("Upload Failed");
              throw err;
           }else{
               console.log("Upload worked");
              let response = "event_photo";
              userData[response] = "SUCCESS RECIEVING EVENT";
              var jsonString = JSON.stringify(userData);
              resolve({statusCode:200, body: jsonString});
           }
        });
    });
};

Please check if you have covered the below.

  1. Create the lambda
  2. Give lambda permission to write put to s3
  3. create an api gateway endpoint with POST or PUT with lambda proxy integration
  4. configured the api gateway to invoke the lambda

Testing

  • when testing the api gateway from aws console, For the request body, you have to give an base64 encoded string of the image

  • when testing from postman, make sure, you select raw under the Body and copy paste the base64 encoded string of the image

hope this helps.

Sign up to request clarification or add additional context in comments.

9 Comments

I've followed all your steps, I think the part I'm getting an error is the parsing. Right now what I'm getting from my event.body is test5=%2F9j%2F4AAQSkZJRgABAQAAAQABAAD%2F2wBDAAEBAQEBAQEBAQ...More characters.. How do I get the entire string after "test5"?
The question is how are you passing that string ,
How are you testing . I think the problem is in how you are testing
I got that string from console.log(event.body); It's just giving me the error "errorMessage": "Unexpected token e in JSON at position 1". Is that string base64 encoded?
What I mean is, how did you test , did you test using postman
|
0

Firstly, if it's a private bucket, you initialise its authorisation details. Allowing uploads to a public s3 bucket without regulation isn't advised.

s3.config.update({
    region: 'ap-southeast-2',
    accessKeyId: process.env.ACCESS_KEY,
    secretAccessKey: process.env.SECRET_KEY
});

Otherwise, you fulfil the s3 upload promise, and here's the async/await way to do it:

try {
    await s3.headObject(params).promise();
    console.log("File found");
    try {
        await s3.upload(params).promise();
        console.log("uploaded successfully");
    }
    catch (error) {
        console.log(error);
        res.status(500).send(error.message);
    }
}
catch (error) {
    console.log(error);
    res.status(500).send(error.message);
} 

Let me know if this works for you.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.