Bluebird: fetch() showing "a promise was created in a handler but was not returned from it" warning

Created on 8 Nov 2015  Â·  40Comments  Â·  Source: petkaantonov/bluebird

I am getting this warning:

a promise was created in a  handler but was not returned from it

For this code:

return new Promise((resolve, reject) => {
    return fetch(`${BASEURL}test/`)
    .then((response) => response.json())
    .then(resolve)
    .catch(reject);
});

Looking over the bluebird docs, I don't understand why I'm getting this warning. My promise handler definitely returns a value. So why the warning?

P.S. You also have a double space in your warning message before the word 'handler'.

Most helpful comment

For others who run into this issue (and are pretty sure they are returning from all handlers)

I am encountering same warning when wrapping Promise.resolve(fetch(...)). I cannot reproduce warning in isolation though. In majority of cases, it works just fine. The warning occurs when two fetch requests are being issued in quick succession. Putting second invocation of wrapped fetch into setTimeout clause avoids the warning. The warning seems to be emitted due to some racecondition, however I do not know enough bluebird internals to actually debug it...

Thanks @jesenko. I ran into the same issue where two fetch() calls are run in quick succession. Wrapping in setTimeout avoids the warning as well. I am using React Native's fetch() polyfill.

I'd suggest reopening this issue...

All 40 comments

Maybe the message is confusing, maybe it's for other code, but in any case you are using the Promise constructor antipattern. It should be just

return fetch(`${BASEURL}test/`)
.then(response => response.json());

Depending on where you used this code it might actually be totally accurate, because you _did_ create a promise (the one returned by catch) that was ignored. The Promise constructor does not return value from the callback, the second return in your code is void.

Thanks for the report. Petka - I'd expect the warning to be about returning from the promise constructor - is this a bug or just two warnings overlapping?

I assume the OP actually did something like

somepromise.then(function() {
    return new Promise((resolve, reject) => {
        return someotherPromise.then(resolve).catch(reject);
    });
});

which could trigger up to 3 warnings:

  1. new Promise constructor antipattern - don't create promises inside the constructor
  2. return … from the constructor callback - the return value is ignored anyway
  3. a promise was created inside a then callback but neither it nor one of its descendants was returned

I changed by code to:

return fetch(`${BASEURL}test/`)
    .then((response) => response.json());
});

And the warning went away.

I still recommend leaving the issue open because the warning message wasn't helpful enough. Even after reading the docs.

Did you read warning explanations page @globexdesigns ?

@petkaantonov Yes, I did. This page: http://bluebirdjs.com/docs/warning-explanations.html says:

Warning: a promise was created in a handler but none were returned from it

This usually means that you simply forgot a return statement somewhere which will cause a runaway promise that is not connected to any promise chain.

However, every promise chain handler in my original code snippet has a return statement. So the warning explanations page alone wasn't helpful in fixing the warning. The issue was not that I didn't have any return statement. The issue seems to be that I was wrapping my calls in a new new Promise() object.

Did you look at the stack trace?

If you call a function inside a handler that creates a new promise that doesn't return it, then there are still promises being created that are not returned to their handlers, even if you had a return statement in the immediate function

I see. So the top of the stack doesn't necessarily represent where the issue is. Ok. Closing. This bug can serve as documentation for those who encounter it in the future.

Actually, this warning is still giving me problems. The reason my original code was written as:

return new Promise((resolve, reject) => {
    return fetch(`${BASEURL}test/`)
    .then((response) => response.json())
    .then(resolve, reject);
});

is because the default Promise response from fetch() doesn't support .finally() since it uses the native browser Promises. So I need to wrap it with bluebird's Promise, to ensure I get all the features I need from the Promise response.

However, adding this wrapper gives me this warning. I'm not sure how else to achieve what I need.

Promise.resolve(fetch(`${BASEURL}test/`))

@tyscorp Unfortunately the warning is still there when doing that.

Does the warning show when you run just that line of code in isolation?

I am encountering same warning when wrapping Promise.resolve(fetch(...)). I cannot reproduce warning in isolation though. In majority of cases, it works just fine. The warning occurs when two fetch requests are being issued in quick succession. Putting second invocation of wrapped fetch into setTimeout clause avoids the warning. The warning seems to be emitted due to some racecondition, however I do not know enough bluebird internals to actually debug it...

@jesenko what fetch polyfill are you using?

@benjamingr I am using 'isomorphic-fetch'. I just checked - apparently in Chrome (where I am encountering the issue) it just resolves to built-it native fetch.

Ran into this as well. @globexdesigns' trials helped me figure out that I needed to dig deeper into the stack trace. Thanks.

Hi I am having the same issue with unwanted warnings showing up in working code. How do I go about disabling the warning?

Here is my code:

cardDataManager.getCardDataPromise = function(){
    console.log('cardDataManager.getCardData...');

    // read th emain bundle path and return the promise
    return new Promise(function(resolve, reject){

        RNFS.readDir(RNFS.MainBundlePath).then((result)=>{
                // console.log('cardDataManager.getCardDataPromise:then...', result);

                // let's find the one named cardData
                var cardData = result.find((el,index,orig)=>{
                    return el.name==='cardData'
                });

                // read the card content list json and return the promise
                RNFS.readFile(cardData.path+'/data/card-content-list.json')
                    .then(JSON.parse)
                    .then((cardList)=>{
                        // console.log('cardData.readDir...',cardList);
                        resolve({
                            docRoot:cardData.path,
                            cardList:cardList
                        });
                    });
            });

    });

}

That's not really an unwanted warning, your code is not taking advantage of chainability of promises using return

Hi @petkaantonov thanks,
I was able to resolve this by adding a return to right before the RNFS.readFile

Sorry, I did not write this code originally, that's why I'm a little confused about it. I'm just upgrading the libraries for the code-base. Let me know if you have a better idea for how to improve this code. Appreciate your help.

I was able to resolve this by adding a return to right before the RNFS.readFile

Yes - and you should also remove the new Promise thing (I guess this threw a warning as well). See http://stackoverflow.com/q/23803743/1048572?what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it

I am also having a difficult time fixinf my promises. I get the following stack error:

Warning: a promise was created in a handler but was not returned from it
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\iron\lib\index.js:409:20
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\iron\lib\index.js:197:9
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hoek\lib\index.js:850:22
    at nextTickCallbackWith0Args (node.js:433:9)
    at process._tickDomainCallback (node.js:403:13)
From previous event:
    at Object.update (users.js:140:14)
    at handler (users.js:132:13)
    at Object.exports.execute.internals.prerequisites.internals.handler.callback [as handler] (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\handler.js:96:36)
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\handler.js:30:23
    at [object Object].internals.Protect.run.finish [as run] (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\protect.js:64:5)
    at exports.execute.finalize (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\handler.js:24:22)
    at each (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\request.js:378:16)
    at iterate (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:36:13)
    at done (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:28:25)
    at request._protect.run (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\validation.js:59:20)
    at [object Object].internals.Any.applyFunctionToChildren.internals.Any._validateWithOptions (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\joi\lib\any.js:657:16)
    at [object Object].root.validate (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\joi\lib\index.js:102:23)
    at Object.internals.input.postValidate [as input] (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\validation.js:131:20)
    at exports.payload (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\validation.js:29:22)
    at each (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\request.js:378:16)
    at iterate (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:36:13)
    at done (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:28:25)
    at request._protect.run (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\validation.js:59:20)
    at [object Object].internals.Any.applyFunctionToChildren.internals.Any._validateWithOptions (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\joi\lib\any.js:657:16)
    at [object Object].root.validate (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\joi\lib\index.js:102:23)
From previous event:
    at method (issueToken.js:51:10)
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\request.js:397:22
    at iterate (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:36:13)
    at Object.exports.serial (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:39:9)
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\request.js:392:15
    at [object Object].internals.Protect.run.finish [as run] (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\protect.js:64:5)
    at [object Object].internals.Request.internals.Request._execute.internals.Request._lifecycle.internals.Request._invoke.callback._protect.run [as _invoke] (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\request.js:390:19)
    at each (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\request.js:375:25)
    at iterate (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:36:13)
    at done (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:28:25)
    at internals.Auth.test.internals.Auth._setupRoute.internals.Auth._authenticate.internals.Auth.payload.finalize (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\auth.js:362:16)
    at each (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\request.js:378:16)
    at iterate (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:36:13)
    at done (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\items\lib\index.js:28:25)
    at onParsed (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\route.js:409:20)
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\lib\route.js:430:20
    at next (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\subtext\lib\index.js:43:16)
    at C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\subtext\lib\index.js:164:20
    at Object.internals.Parser.internals.Parser.parse.decoder.once.writeFile.internals.Parser.raw.decoder.once.internals.jsonParse (C:\NodeServer\hapi-react-starter-kit\hapi-react-starter-kit\node_modules\hapi\node_modules\subtext\lib\index.js:281:12)

This is my code for those lines:

    if ( switchLocale ) {
      client.sismemberAsync(key + ':unique:ids', user.id)
      .then( () => {
        return client.hsetAsync(key + ':data:' + user.id, 'locale', request.payload.locale)
        .then( () => {
          return callback({ ok: 'OK', locale: request.payload.locale });
        })
        .catch( e => {
          console.error('Error setting user locale: ', e.stack);
          return callback(null);
        });
      })
      .catch( e => {
        console.error('Error finding user: ', e.stack);
        return callback(null);
      });
    } 

@petkaantonov Where is that I am missing the return statement?

I'm getting this warning when using RxJS's flatMap operator, but only in flatMap observers that are chained after the first flatMap observer is executed.

http://stackoverflow.com/questions/34728324/how-do-i-get-rid-of-a-bluebird-warning-when-chaining-more-than-one-flatmap-opera

I solved it. All Promises inside other promises should have a return

I am now struggling with the same.

If somebody can help me figure out where the promise is leaking, it would be much appreciated!

Complete test code:

'use strict';

var promise = require('bluebird');
var spex = require('spex')(promise);

function factory(index) {
    if (index < 2) {
        return promise.resolve(index);
    }
}

spex.sequence(factory)
    .then(data=> {
        console.log("success");
    })
    .catch(error=> {
        console.log("error");
    });

Results in:

Warning: a promise was created in a handler but was not returned from it
    at Object.factory (D:\NodeJS\tests\test4.js:8:24)
    at loop (D:\NodeJS\tests\node_modules\spex\lib\utils.js:69:44)
    at Object.resolve (D:\NodeJS\tests\node_modules\spex\lib\utils.js:90:9)
    at loop (D:\NodeJS\tests\node_modules\spex\lib\ext\sequence.js:106:28)
    at next (D:\NodeJS\tests\node_modules\spex\lib\ext\sequence.js:160:25)
    at $utils.resolve.call.reject.index (D:\NodeJS\tests\node_modules\spex\lib\ext\sequence.js:144:25)
    at loop (D:\NodeJS\tests\node_modules\spex\lib\utils.js:86:17)
    at D:\NodeJS\tests\node_modules\spex\lib\utils.js:80:25
    at processImmediate [as _immediateCallback] (timers.js:383:17)
From previous event:
    at loop (D:\NodeJS\tests\node_modules\spex\lib\utils.js:77:22)
    at Object.resolve (D:\NodeJS\tests\node_modules\spex\lib\utils.js:90:9)
    at loop (D:\NodeJS\tests\node_modules\spex\lib\ext\sequence.js:106:28)
    at D:\NodeJS\tests\node_modules\spex\lib\ext\sequence.js:184:9
From previous event:
    at promise (D:\NodeJS\tests\node_modules\spex\lib\index.js:96:24)
    at Object.sequence (D:\NodeJS\tests\node_modules\spex\lib\ext\sequence.js:100:12)
    at Object.sequence (D:\NodeJS\tests\node_modules\spex\lib\ext\sequence.js:193:29)
    at Object.<anonymous> (D:\NodeJS\tests\test4.js:12:6)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Function.Module.runMain (module.js:441:10)
    at startup (node.js:139:18)
    at node.js:968:3

success

I've been all over the implementation of spex.sequence with a fine brush, and still cannot see where the promise is leaking.

+1 Experiencing the same issue

For others who run into this issue (and are pretty sure they are returning from all handlers)

I am encountering same warning when wrapping Promise.resolve(fetch(...)). I cannot reproduce warning in isolation though. In majority of cases, it works just fine. The warning occurs when two fetch requests are being issued in quick succession. Putting second invocation of wrapped fetch into setTimeout clause avoids the warning. The warning seems to be emitted due to some racecondition, however I do not know enough bluebird internals to actually debug it...

Thanks @jesenko. I ran into the same issue where two fetch() calls are run in quick succession. Wrapping in setTimeout avoids the warning as well. I am using React Native's fetch() polyfill.

I'd suggest reopening this issue...

The warning has been improved in 3.4.3

I was getting the same warning because I wanted to reject some cases fetch resolved. Think I found a good way to return a bb promise from fetch without getting that warning.

let status
return fetch(url, finalParams).then(
    (res) => {
        status = res.status
        return res.json()
    }
)
.then(
    (res) => {
        let bbPromise
        if (_inRange(status, 200, 300)) {
            bbPromise = Promise.resolve(res)
        } else {
            bbPromise = Promise.reject(res)
        }
        return bbPromise
    }
)
.catch(
    (error) => Promise.reject(error)
)

Sorry to add to this old thread, but the explanation provided here is the best I've seen: http://stackoverflow.com/a/39603167/461263

It might just be hard to parse the error message as a sentence, which is sort of clumsy in terms of prose.

I have been staring at my code for a long time, and I still don't see where it's having a problem:

emit(eventName, eventData) {
    return new Promise(
        (resolve, reject) => {
            this._ioClient.emit(eventName, eventData, (result) => {
                if (result.error) {
                    reject(new Error(`Socket error: ${result.message}`));
                }
                else {
                    resolve(result);
                }
            });
        }
    );
}

I tried adding explicit returns both to the Promise constructor callback and to the inner emit callback, and had no luck. Tried adding explicit returns to upstream code that eventually calls this. Nothing is eliminating the warning.

The line that the warning points to is in some React code somewhere, which does not itself appear to be using promises.

@turnerhayes you need to return resolve(result); and return reject(new Error(`Socket error: ${result.message}`));

most of this misunderstandings with promises are one of these 3 problems:

  • you aren't returning your resolve/reject
  • you aren't returning the wrapping function/promise
  • arrow functions.... val => val == (val) => (val) == val => { return val; }

This last the one, is the one that people (myself included) often forget... when switching to multiline you must add a return;

I am personally getting this warning when no promises in my chain are missing any returns. It's a very short trip to my passport localStrategy but it's suddenly choking on return done(null,user); after 0 changes were made to the code or deps.

"Warning: a promise was created in a handler at /config/passport.js:30:18 but was not returned from it, see http://goo.gl/rRqMUw" done() is also known as next() or cb() it's simply express' callback function that passes data to the next middleware or endpoint.

I turned on stack trace... it STARTS at res.json(); I have searched all of my ".then"s and ensured all my promises were completing. The app works great the warnings point to nothing wrong. I checked every file in the stack strace. I don't understand why this is happening and why this points to callback/function code that functions properly, NOT any promises.

I also don't understand why this started happening after changing some configuration files, then reverting them. No deps updated, no code changes, it all works, just these damn warnings.

Why do I need to return resolve/reject? Doesn't the promise resolution depend entirely on calling resolve() and reject(), and not on their return values?

@turnerhayes yes you are indeed correct but the promise must return something. This is a much better AND cleaner approcah

if(data) {
  return resolve(data);
} else {
  return reject('No data exists');
}

than others have widely adopted...

if(data) {
  resolve(data);
  return null;
} else {
  reject('No data exists');
  return null;
}

Either should work to resolve your issue.

You'll also this method extremely useful making nice tidy .then()s using arrow functions....
.then(result => resolve(result));

I am getting a warning I can't silence where the promise does return something... simply because it's running inside a forEach... it points to the forEach as not returning a promise, but the promise inside does return resolve(data) as well as it being returned from the forEach (not really needed, but hoped it would silence the warning).

Now I have actually moved the loop to just operate on the data and switched to a bulk create... now it points to the bulkCreate method which is followed by a then returning the resolved data. These warnings are impossible to track down and fix. Some of them are just plain wrong and can't be fixed... others appear periodically when they feel like showing up. I ALWAYS have to use node --trace-warnings now and it still gives me a lot of useless data.

AND everything works fine!! It's just littering my logs and wasting valuable time. When will this be fixed?

There is no new promise inside the "then", all it does is resolve what it's passed.

Oh man... after trying nearly everything in the world... I saw @bergus comment above and looked again at my code... I was using the "Promise constructor antipattern" returning a Promise from inside a constructor.

I think that a lot of this gets blamed on ignorance of how Promises work... But really the issue is improperly reported errors, that are unreliable at best. These were all over my code and worked great most of the time... but sometimes I would get stuck because it was pointing me to arbitrary places in the code. Sometimes I could make unrelated changes and get them to cease or begin.

If there is clearly an anti-pattern for this, your error reporting can test for it and point us to the right place rather than sending us on a wild goose chase. Or even better... not allow a new Promise being created inside the constructor.

@petkaantonov I will repeat the my very serious inquiry: When will this be addressed?

It's pretty easy to say go RTFM or learn Promises better which has been much of the theme across your issues... but much harder to update the error reporting to work properly, so that you can use the errors to document and educate people on how your library works. I see that you have made some progress in error reporting... but there is still much to be done here.

@jeremybradbury have you tried turning on warnings?

And in general - no one is blaming people for not knowing how promises work or telling anyone to RTFM. We're all in consensus that bluebird should always do the _useful_ thing for the developer.

Was this page helpful?
0 / 5 - 0 ratings