winstonjs/winston · warning

winston: exitOnError cannot be true with no rejection handle

Error message

winston: exitOnError cannot be true with no rejection handlers.

What it means

winston's RejectionHandler catches unhandled promise rejections. When there are no rejection-handler transports registered and logger.exitOnError is true, winston warns that exiting on error is impossible because nothing would consume/log the rejection, then overrides doExit to false so the process keeps running.

Source

Thrown at lib/winston/rejection-handler.js:179

   * Logs all relevant information around the `err` and exits the current
   * process.
   * @param {Error} err - Error to handle
   * @returns {mixed} - TODO: add return description.
   * @private
   */
  _unhandledRejection(err) {
    const info = this.getAllInfo(err);
    const handlers = this._getRejectionHandlers();
    // Calculate if we should exit on this error
    let doExit =
      typeof this.logger.exitOnError === 'function'
        ? this.logger.exitOnError(err)
        : this.logger.exitOnError;
    let timeout;

    if (!handlers.length && doExit) {
      // eslint-disable-next-line no-console
      console.warn('winston: exitOnError cannot be true with no rejection handlers.');
      // eslint-disable-next-line no-console
      console.warn('winston: not exiting process.');
      doExit = false;
    }

    function gracefulExit() {
      debug('doExit', doExit);
      debug('process._exiting', process._exiting);

      if (doExit && !process._exiting) {
        // Remark: Currently ignoring any rejections from transports when
        // catching unhandled rejections.
        if (timeout) {
          clearTimeout(timeout);
        }
        // eslint-disable-next-line no-process-exit
        process.exit(1);
      }

View on GitHub (pinned to ff0b79de85)

Solutions

  1. Add at least one rejection handler transport: logger.rejections.handle(new winston.transports.File({ filename: 'rejections.log' })).
  2. Set exitOnError to false (or an appropriate callback) if you intentionally do not want the process to exit on rejections.
  3. Verify the rejection handler's transports array is populated (console-print logger.rejections) before relying on exit behavior.

Example fix

// before
const logger = winston.createLogger({ exitOnError: true, rejections: true, transports: [] });
// after
const logger = winston.createLogger({
  exitOnError: true,
  rejections: { handledBy: [new winston.transports.File({ filename: 'rejections.log' })] }
});
Defensive patterns

Strategy: validation

Validate before calling

// Validate rejection transports before relying on exitOnError
if (logger.exitOnError === true && (!logger.rejections || logger.rejections.transports.length === 0)) {
  throw new Error('exitOnError=true requires at least one rejection handler transport');
}

Prevention

When it happens

Trigger: An unhandled promise rejection occurs while logger.exitOnError (or exitOnError callback returns true) but logger.rejections handledBy / the handler has an empty transports list — i.e. rejections are being handled by the handler but no rejection transports were added.

Common situations: Enabling logger.exceptions.handle() but forgetting logger.rejections.handle(transport); misconfiguring a logger where the rejection handler exists (e.g. rejections: true in createLogger) with no transports; assuming exitOnError guarantees process exit on rejections.

Related errors


AI-assisted analysis of winstonjs/winston@ff0b79de85 (2026-08-31). Data as JSON: /api/errors/b3f85b4b8fd82187. Report an issue: GitHub.