Serverless-offline: UnhandledPromiseRejectionWarning - createLambdaContext

Created on 15 May 2019  路  17Comments  路  Source: dherault/serverless-offline

Hi,

I have a simple code and i am running into this error :

(node:64802) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'done' of undefined at createLambdaContext (/Users/suri/Documents/Projects/Aptimise/subscription-services/node_modules/serverless-offline/src/index.js:671:44) at fail (/Users/suri/Documents/Projects/Aptimise/subscription-services/node_modules/serverless-offline/src/createLambdaContext.js:18:21) at process._tickCallback (internal/process/next_tick.js:68:7) (node:64802) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

my code

`"use strict";

const fetch = require("node-fetch");

module.exports.handler = async (event, context, callback) => {
try {
const response = await fetch("https://reqres.in/api/users").catch(err =>
callback(err)
);
const data = await response.json();
console.log(data);
// if (!response.ok) {
// // NOT res.status >= 200 && res.status < 300
// return { statusCode: response.status, body: response.statusText };
// }
//const data = await response.json();

// callback(null, JSON.stringify({ msg: data }))

} catch (err) {
//callback(err);
}
//console.log(data);
callback(null, {
statusCode: 200,
body: JSON.stringify({ data: "somedata" })
});
};
`

Packages -

"serverless-offline": "^4.10.2"
"node-fetch": "^2.5.0",
"serverless: "1.42.3"

What am i doing wrong here ?

Most helpful comment

My fix addressed the truly async promise scenario, but it looks like @mkondel issue is a truly async callback scenario. I've got a failing test that proves this out:

    it('should support handler that defers and uses done()', done => {
      const offline = new OfflineBuilder(new ServerlessBuilder(serverless))
        .addFunctionHTTP('index', {
          path: 'index',
          method: 'GET',
        }, (request, context, serverlessDone) => 
          setTimeout(() => 
            serverlessDone({
              statusCode: 200,
              body: JSON.stringify({ message: 'Hello World' }),
            }), 
          10)
        ).toObject();

      offline.inject({
        method: 'GET',
        url: '/index',
        payload: { data: 'input' },
      }, res => {
        expect(res.headers).to.have.property('content-type').which.contains('application/json');
        expect(res.statusCode).to.eq(200);
        expect(res.payload).to.eq('{"message":"Hello World"}');
        done();
      });
    });

Put that right after the test "should support handler returning Promise that defers" in offline.js and when you run tests, you'll see it fails with the error everyone is seeing. I don't know enough about that memory leak fix to know _why_ the finally block is the way it is, so I'm not sure what to do about this specific scenario. I can personally ignore it because I'm using promises all the way down.

@mkondel, you can work around your problem by replacing line 5 of lambdas/index.js with:

module.exports.react = (event, context) => sls(server, { binary: binaryMimeTypes })(event, context);

It's not pretty, but it looks like serverless-http is getting the done() function from serverless-offline and assuming that you want to use a callback and not a promise. serverless-offline is giving you the option to use either, and figures out which you wanted to use by whether you get a promise back or not. So that puts you in the currently broken scenario.

All 17 comments

Same over here.

(node:14604) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'done' of undefined
    at createLambdaContext (/project/node_modules/serverless-offline/src/index.js:671:44)
    at fail (/project/node_modules/serverless-offline/src/createLambdaContext.js:18:21)
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:14604) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)

Seems like this line -> if (this.requests[requestId].done) { in serverless-offline/src/index.js:671 raises the exception.

EDIT
Added the following above the faulty line in there and seemed to work for me.

this.requests[requestId] = this.requests[requestId] || {};

I can also confirm this. It was introduced on version 4.10.1. Version 4.10.0 works OK.

Function:

module.exports.handler = async event => {
  try {
    // ...

    await someDatabaseQuery(); // Fulfills OK

    // ...

    return {
      // Success response...
    };
  } catch (err) {
    return {
      // Error response...
    };
  }
};

Output:

(node:8187) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'done' of undefined
    at createLambdaContext (/project/node_modules/serverless-offline/src/index.js:662:44)
    at fail (/project/node_modules/serverless-offline/src/createLambdaContext.js:18:21)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:229:7)
(node:8187) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)

Please check out the v4.10.3 and tell us if it is ok now :)

I can confirm on my system v4.10.3 works fine :) Thanks.

Confirmed works fine with "serverless-offline": "^4.10.3" 馃憤 Thanks @dherault

Thank @Andorbal 馃憤

Hi i'm having same issue, when run with NestJs here. Even if with "^4.10.3".
https://github.com/fshidemo/serverless-nestjs

I think:
this.requests[requestId] = this.requests[requestId] || {};

or something like this still need to control this situation

if (requestId in this.requests) {
// do some logic
} else {
// do else
}

The same error still persists with ^4.10.3.

It seems to be working fine for me in latest 4.10.3.

Can be verified that it's not working with 4.10.3 in this demo: https://github.com/mkondel/serverless-offline-test

It's still failing for me in 4.10.3 as well.

(node:2229) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'done' of undefined
    at createLambdaContext (/home/circleci/project/node_modules/serverless-offline/src/index.js:671:44)
    at handler.catch.then.then.response (/home/circleci/project/functions/dist/service/src/handlers/webpack:/packages/service/src/lib/apiGatewayHandler.ts:133:1)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:229:7)

My fix addressed the truly async promise scenario, but it looks like @mkondel issue is a truly async callback scenario. I've got a failing test that proves this out:

    it('should support handler that defers and uses done()', done => {
      const offline = new OfflineBuilder(new ServerlessBuilder(serverless))
        .addFunctionHTTP('index', {
          path: 'index',
          method: 'GET',
        }, (request, context, serverlessDone) => 
          setTimeout(() => 
            serverlessDone({
              statusCode: 200,
              body: JSON.stringify({ message: 'Hello World' }),
            }), 
          10)
        ).toObject();

      offline.inject({
        method: 'GET',
        url: '/index',
        payload: { data: 'input' },
      }, res => {
        expect(res.headers).to.have.property('content-type').which.contains('application/json');
        expect(res.statusCode).to.eq(200);
        expect(res.payload).to.eq('{"message":"Hello World"}');
        done();
      });
    });

Put that right after the test "should support handler returning Promise that defers" in offline.js and when you run tests, you'll see it fails with the error everyone is seeing. I don't know enough about that memory leak fix to know _why_ the finally block is the way it is, so I'm not sure what to do about this specific scenario. I can personally ignore it because I'm using promises all the way down.

@mkondel, you can work around your problem by replacing line 5 of lambdas/index.js with:

module.exports.react = (event, context) => sls(server, { binary: binaryMimeTypes })(event, context);

It's not pretty, but it looks like serverless-http is getting the done() function from serverless-offline and assuming that you want to use a callback and not a promise. serverless-offline is giving you the option to use either, and figures out which you wanted to use by whether you get a promise back or not. So that puts you in the currently broken scenario.

@Andorbal thank you for that work around, I will test it out.

Edit: Your fix now works in the demo and in my full app!

@Andorbal Can you PR a fix for this bug this week ? Otherwise I'll revert to 4.10.0

What about v4.10.4?

@dherault seems to work for me.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MEGApixel23 picture MEGApixel23  路  4Comments

Ali-Dalal picture Ali-Dalal  路  4Comments

JimLynchCodes picture JimLynchCodes  路  4Comments

dnalborczyk picture dnalborczyk  路  3Comments

davidroman0O picture davidroman0O  路  4Comments