'Not able to catch error from AWS sdk [S3]

Im trying to download a file from S3 which doesn't exist on S3. I expect a error in this scenario and im also getting that error from aws-sdk i.e.

**/vagrant/node_modules/aws-sdk/lib/request.js:31 throw err; ^

NoSuchKey: The specified key does not exist.**

But the issue is, im not able to catch this error. If you check the code below, my listener request.on gets called and when i call reject in that the promise doesn't return from method downloadFontInfoFileFromS3 with reject.

Is there any way i can catch the error and gracefully reject the promise from downloadFontInfoFileFromS3 function?

downloadFontInfoFileFromS3(fileKey) {
    return new Promise((resolve, reject) => {
        const sThree = new awsSDK.S3();
        const options = {
            Bucket: awsConf.bucket,
            Key: fileKey,
        };
        const downloadFilePath = SOME_PATH
        const file = fs.createWriteStream(downloadFilePath);

            const request = sThree.getObject(options);

            const download = request
                .createReadStream().pipe(file);

            // called when error in aws-sdk
            request.on('error', (error) => {
                logger.error('Failed to download file from S3:', error.message);
                reject(error);
            });

            download.on('error', (error) => {
                reject(error);
            });

            download.on('finish', () => {
                resolve(downloadFilePath);
            });
            // the synchronous code that we want to catch thrown errors on
    });
}


Solution 1:[1]

I ran into this issue as well. Turns out I wasn't setting the error handler in the correct place.

Currently, you have:

// INCORRECT. Won't work

const download = request.createReadStream().pipe(file);

download.on('error', (error) => {
    reject(error);
});

But you actually need to set the error handler on the stream, before you begin piping. Like this:

// Correct!

const download = request.createReadStream(); // notice the `.pipe()` has been removed

download.on('error', (error) => {
    reject(error);
});

// now you can begin piping to the file
requestStream.pipe(file);

If you try setting the event handler after the pipe has begun, the error will "bypass" any try/catch or Promise .catch handlers you specify. Quite frustrating!

Check out this GitHub issue for another example.

Solution 2:[2]

const data = s3.getObject({ Bucket: process.env.AWS_BUCKET_NAME, Key: url }).createReadStream();

data.on("error", (err) => {
    if (err)
        return next(customError("Invalid Url", 400));
});
data.pipe(res);

Right Because Error is occourd when data in pipe.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jknotek
Solution 2 Aadarsh Kumar