3

I am sincerely puzzled by this. I am simply trying to invoke a Lambda function from within a Node JS application and perform image resizing on it. The invocation succeeds and the function is called (I can pass parameters to it and see them returned), however when I attempt to use Sharp for image resizing, I get the strange error that the input file is missing. It's not, as I can definitively confirm that the buffer is indeed passed to the Lambda.

I can confirm that using Sharp locally works. In the invocation I am JSON stringifying the payload, and I can confirm that the parameters are indeed passed to and are received by the Lambda. I am mapping them correctly from the first 'event' argument in the invocation. However the inclusion of Sharp within the Lambda just simply breaks.

I have created a new 'Sharp' project and have installed the node modules. These are packaged with the Lambda's index function into an archive and this is uploaded into the zip. The one thing that is quite different is that in order to use Sharp inside of Lambda, I had to install the linux version.

npm install --arch=x64 --platform=linux sharp

I have a test script in the Lambda where I have copied over a complete payload including a proper buffer. Both the test script and my local machine throw the same error:

{
  "errorType": "Error",
  "errorMessage": "Input file is missing",
  "trace": [
    "Error: Input file is missing"
  ]
}

This is my Lambda function.

const sharp = require('sharp');

exports.handler = async (event) => {
  return await sharp(event.buffer)
    .resize({
      width: event.maxWidth,
      height: event.maxHeight,
      fit: 'inside',
      withoutEnlargement: true
    })
    .jpeg({
      quality: 80
    })
    .toBuffer();
}

And this is my invocation.

const thumbImage = await lambda.invoke({
   FunctionName: 'sharp-resize',
   Payload: JSON.stringify({ buffer: file.buffer, maxWidth, maxHeight })
}).promise();

Any ideas or assistance would be appreciated.

  • Can you share the entire error message you're getting? Have you tried using an amazonlinux2 docker image to install the dependencies to ensure that you're installing the compiled versions for the correct platform? – stijndepestel Aug 04 '21 at 08:32

1 Answers1

0

I finally figured this out, and it really was such a simple thing. When stringifying the buffer, the Lambda needed to recreate the buffer from the event.buffer property. When the function returned the resized image, I stringified it again before recreating the buffer upon receipt. Then it was a simple matter of posting the new buffer back to S3.

My final Lambda:

const sharp = require('sharp');

exports.handler = async (event) => {
  let buffer = Buffer.from(event.buffer.data);

  buffer = await sharp(Buffer.from(buffer))
    .resize({
       width: event.maxWidth,
       height: event.maxHeight,
       fit: 'inside',
       withoutEnlargement: true
    })
    .jpeg({
       quality: 80
    })
    .toBuffer();
  }
  
  return {
    statusCode: 200,
    headers: {
      "Access-Control-Allow-Origin": "*"
    },
    buffer: JSON.stringify(buffer)
  };
}

And my invocation and posting to S3:

const thumbImage = await lambda.invoke({
  FunctionName: 'sharp-resize',
  Payload: JSON.stringify({ extension, buffer: file.buffer, maxWidth, maxHeight })
}).promise();

const payload = JSON.parse(thumbImage.Payload);
const buffer = JSON.parse(payload.buffer);
const parsedBuffer = Buffer.from(buffer.data);
response.thumbImage = await uploadToS3({ key: amazonS3ThumbKey, file: parsedBuffer });