node.jsaws-lambdaimagemagickgm

TypeError: Cannot read property 'width' of undefined gm library


Previously, I had followed this link to successfully create thumbnail images using AWS Lambda. The node version was 8.10.

Now, as AWS will be deprecating any application with this node version, i have to update the node version to 10.x.

We are contacting you as we have identified that your AWS Account currently has one or more Lambda functions using Node.js 8.10, which will reach its EOL at the end of 2019.

What’s happening?

The Node community has decided to end support for Node.js 8.x on December 31, 2019 1. From this date forward, Node.js 8.x will stop receiving bug fixes, security updates, and/or performance improvements. To ensure that your new and existing functions run on a supported and secure runtime, language runtimes that have reached their EOL are deprecated in AWS 2.

For Node.js 8.x, there will be 2 stages to the runtime deprecation process:

  1. Disable Function Create – Beginning January 6, 2020, customers will no longer be able to create functions using Node.js 8.10

  2. Disable Function Update – Beginning February 3, 2020, customers will no longer be able to update functions using Node.js 8.10

After this period, both function creation and updates will be disabled permanently. However, existing Node 8.x functions will still be available to process invocation events.

What do I need to do?

We encourage you to update all of your Node.js 8.10 functions to the newer available runtime version, Node.js 10.x[3]. You should test your functions for compatibility with the Node.js 10.x language version before applying changes to your production functions.

What if I have issues/What if I need help?

Please contact us through AWS Support [4] or the AWS Developer Forums [5] should you have any questions or concerns.

So, i have updated my node version to 10.17.0 and deploy the package again in AWS Lambda. Now, if any image has been uploaded to S3 and aws lambda tries to convert the image into a thumbnail, it shows below error:

enter image description here

This is the full code:

// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm')
            .subClass({ imageMagick: true }); // Enable ImageMagick integration.
var util = require('util');

// constants
var MAX_WIDTH  = 100;
var MAX_HEIGHT = 100;

// get reference to S3 client 
var s3 = new AWS.S3();

exports.handler = function(event, context, callback) {
    // Read options from the event.
    console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
    var srcBucket = event.Records[0].s3.bucket.name;
    // Object key may have spaces or unicode non-ASCII characters.
    var srcKey    =
    decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));  
    var dstBucket = srcBucket + "resized";
    var dstKey    = "resized-" + srcKey;

    // Sanity check: validate that source and destination are different buckets.
    if (srcBucket == dstBucket) {
        callback("Source and destination buckets are the same.");
        return;
    }

    // Infer the image type.
    var typeMatch = srcKey.match(/\.([^.]*)$/);
    if (!typeMatch) {
        callback("Could not determine the image type.");
        return;
    }
    var imageType = typeMatch[1].toLowerCase();
    if (imageType != "jpg" && imageType != "png") {
        callback(`Unsupported image type: ${imageType}`);
        return;
    }

    // Download the image from S3, transform, and upload to a different S3 bucket.
    async.waterfall([
        function download(next) {
            // Download the image from S3 into a buffer.
            s3.getObject({
                    Bucket: srcBucket,
                    Key: srcKey
                },
                next);
            },
        function transform(response, next) {
            gm(response.Body).size(function(err, size) {
                // Infer the scaling factor to avoid stretching the image unnaturally.
                var scalingFactor = Math.min(
                    MAX_WIDTH / size.width,
                    MAX_HEIGHT / size.height
                );
                var width  = scalingFactor * size.width;
                var height = scalingFactor * size.height;

                // Transform the image buffer in memory.
                this.resize(width, height)
                    .toBuffer(imageType, function(err, buffer) {
                        if (err) {
                            next(err);
                        } else {
                            next(null, response.ContentType, buffer);
                        }
                    });
            });
        },
        function upload(contentType, data, next) {
            // Stream the transformed image to a different S3 bucket.
            s3.putObject({
                    Bucket: dstBucket,
                    Key: dstKey,
                    Body: data,
                    ContentType: contentType
                },
                next);
            }
        ], function (err) {
            if (err) {
                console.error(
                    'Unable to resize ' + srcBucket + '/' + srcKey +
                    ' and upload to ' + dstBucket + '/' + dstKey +
                    ' due to an error: ' + err
                );
            } else {
                console.log(
                    'Successfully resized ' + srcBucket + '/' + srcKey +
                    ' and uploaded to ' + dstBucket + '/' + dstKey
                );
            }

            callback(null, "message");
        }
    );
};

The error is basically in this line:

gm(response.Body).size(function(err, size) {
                // Infer the scaling factor to avoid stretching the image unnaturally.
                var scalingFactor = Math.min(
                    MAX_WIDTH / size.width, // In this line where the size is undefined
                    MAX_HEIGHT / size.height
                );

The node version of 8.10 is working perfectly. I have no clue what to do in this case. I have the memory size of 1024MB in the configuration

Can anyone point me out on where should i change? Thanks in advance.


Solution

  • The problem is, that gm is not supported anymore with NodeJS 10.x: https://github.com/aheckmann/gm/issues/752.

    So there will be problems here. It seems like you have to create and use a Lambda layer to fix it. But the real problem occurs, if you are using Lambda@Edge, since Lambda layers are not allowed here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html