0

I have simple little program which defines two functions as variables. These functions both return RSVP Promises so that they can be chained together as I have done below. I use this pattern often but in this case I'm running into madness ...

var opChown = function() { ... };
var opChgrp = function() { ... };

debug('chown: ' + opChown);
debug('chgrp: ' + opChgrp);
// Chain permission operations          
opChown()
    .then(opChgrp())
    .then(function() {
        debug('resolving parent promise');
        resolve();
    })
    .catch(function(err) {
        debug('rejecting parent promise');
        reject(err);
    }
);

While my debug statements clearly show that the two functions are in fact defined, when I execute them I get an unhandled exception:

TypeError: undefined is not a function

Please help me losing my mind. Any and all suggestions welcome.


For some additional context here is the definition of opChown:

var opChown = function() {
    return new RSVP.promise(function(resolve,reject) {
        debug('opChown');
        if(options.ignoreChown) {
            resolve();
        } else {
            var chown = shell('chown',['-R', downgradedUser, destDir]);
            debug('chown command executed; user permission is "%s"', downgradedUser);
            chown.on('exit',function(code) {
                if(code !== 0) {
                    var errMessage = 'Build [' + code + ']:' + ' problems changing ownership on "' + destDir + '" directory to ' + downgradedUser + '.';
                    debug('Problem with chown: %s', code);
                    reject({operation:'chown', message: errMessage});
                } else {
                    console.log(' - %s executed, user permissions changed to %s', chalk.bold('chown'), chalk.bold(downgradedUser));
                    resolve();
                }
            }); // end chown
        }
    });
}; // end opChgOwn          

Now based on @bergi's great pointer that the stacktrace is indeed available to me on Node's 'uncaughtException' event, here is the stacktrace which clearly points to the problem being within the opChown function rather than the function itself:

TypeError: undefined is not a function
    at opChown (/lib/broccoli-watcher.js:117:13)
    at ChildProcess.<anonymous> (/lib/broccoli-watcher.js:167:5)
    at ChildProcess.emit (events.js:98:17)
    at Process.ChildProcess._handle.onexit (child_process.js:809:12)
ken
  • 8,763
  • 11
  • 72
  • 133
  • For what it's worth, the code sample I have listed above is part of a RSVP promise itself. Note the catch function which calls `reject(err)` ... this is passing the reject to the parent RSVP promise. – ken Sep 03 '14 at 12:18
  • You don't need to do that at all; you can simply return the inner promise from the outer promise's `then()` callback – SLaks Sep 03 '14 at 12:20
  • From what line do you get the error, with what stacktrace? Please add some debugging details. – Bergi Sep 03 '14 at 12:54
  • @bergi it is picked up by Node's 'uncaughtException' event: `process.on('uncaughtException', atException);` I don't think there is any stacktrace in the error object that is passed in. I will say, though, that I've narrowed it down to the initial call to `opChown()`. I did this by removing the whole then/catch chain of functions. Same error. – ken Sep 03 '14 at 12:59
  • Node's error objects should have a `.stack` property; try to print it. – Bergi Sep 03 '14 at 13:03
  • @bergi you are a godsend, it does indeed have a stack property ... not sure how I missed that but no more stumbling around in the dark :) – ken Sep 03 '14 at 13:05

2 Answers2

2

Although I had expected the error message to be something like undefined is not a constructor, it looks as if the line

    return new RSVP.promise(function(resolve,reject) {

should rather be

    return new RSVP.Promise(function(resolve,reject) {
//                  ^

Notice that @SLaks spotted a mistake as well: then takes callback functions. You probably want to use

opChown().then(opChgrp)…
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Ahhh capital letters. The bain of my existence. Thanks for all the help @bergi. – ken Sep 03 '14 at 13:13
1
.then(opChgrp())

You just called opChgrp immediately and passed its result to then().

Since it doesn't return anything, you get an error.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Yes both `opChown` and `opChgrp` immediately return RSVP promises which then results in the first function parameter in `then()` being called. By not stating a second function, you can catch all rejections at the bottom of the stack as I've done with the catch block. – ken Sep 03 '14 at 12:24
  • I have added the full definition of the `opChown` function for some more context. – ken Sep 03 '14 at 12:27
  • In fact, to further illustrate the nature of the problem ... if I remove all `.then()` calls and JUST call `opChown();` I still get the undefined error. – ken Sep 03 '14 at 12:32
  • In fact, `then` must not throw an error if you pass `undefined` - even if it's a common mistake though and the script will probably mis-behave, it's not an error. – Bergi Sep 03 '14 at 12:56
  • @bergi sorry I'm not following ... what I'm saying is I removed all reference to `then()`. I am simply calling the function but still getting the same undefined error. Basically it seems to be complaining that opChown is undefined (although its clearly not). – ken Sep 03 '14 at 13:02
  • @ken: The reply was to SLaks - the piece of code is a mistake, but not the source of the error you experience. I rather believe that some function that is used in `opChown` is undefined. – Bergi Sep 03 '14 at 13:05
  • @Bergi ... based on your very helpful pointer about the stack I should be able to sort this and your idea that it's a call within `opChown` looks to be correct. – ken Sep 03 '14 at 13:08