Skip to content

problems with Promise error handling in plugin registration #3381

@5c077yP

Description

@5c077yP

Hey,

I recently experienced an issue, when registering plugins using promise style and the plugin itself is not calling next with a proper Error Object. (Btw. I'm using the latest hapi version 15.2.0.)

Let's say I'm registering plugins like this

server.on('start', () => console.log('server started successfully'));

return server.register(plugins) // plugins is a list of plugins
  .then(() => server)
  .catch((err) => {
    console.errror('could not register plugins', err);
    process.exit(1);
  })

now imagine a bad plugin like this:

class BadError {
  constructor(message) {
    this.message = message;
  }
}

const badPlugin = {
  register(server, options, next) {
    return next(new BadError('bad-error'));
  }
};

badPlugin.register.attributes = { name: 'bad-plugin' };

and my list of plugins:

const plugins = [
  /* .. `set-of-plugins-1` */,
  { register: badPlugin },
  /* .. `set-of-plugins-2` */
]

What I thought is, that the server exits with code 1, but what happens is the server starts, logs server started successfully. Now the server keeps running and all set-of-plugins-1 are running but none of set-of-plugins-2.

I checked the code and what I can tell is, that when calling the server.register function without a callback it's using the Promise.wrap, which re-calls the function with a callback. The register function now iterates through all plugins using Items.serial, which itself breaks the serial flow whenever any argument is passed to the next callback. But now this "wrapped" promise callback only expects one argument, which if an Error is rejected otherwise resolved.

In the described case, the plugin is unfortunately not calling next with a proper Error Object. Now the Items.serials breaks the flow, it calls the wrapped promise callback, but this callback itself doesn't recognise the error and instead just resolves the Promise. In my case this leads to a situation where all plugins before the "bad" one are registered fine, but the rest not and the server keeps running.

In this case I'm not controlling the errors, but I could check the error and wrap it into a real Error Object. Another solution could be to check in the server.register().then() if any argument is passed to the then function it can only be an error (i think).

Of course it would be great if from hapi itself this would be reported as an error, maybe there should be a 4th argument to Promise.wrap (e.g. nodeStyleCallback = false) which if a first argument is given rejects and otherwise resolves with the second argument, because in the case of the plugin registration always only an error (or nothing) is passed to the callback, but of course i'm not super deeply into the code, so this is just an idea.

Thanks for reading.

Metadata

Metadata

Assignees

Labels

bugBug or defect

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions