Ok. So, here is how it works. async.waterfall expects each task to call its cb() in order to pass the control to the next callback. But if one of the tasks in the array passes an error to the callback i.e. cb(err); then the last callback executes immediately, which is next in your case. So, instead of calling next() from your second task you should just call cb1(err) which will invoke the final callback i.e. next.