winstonjs/winston · warning

options.stream will be removed in winston@4. Use winston.tra

Error message

options.stream will be removed in winston@4. Use winston.transports.Stream

What it means

The File transport constructor accepts a deprecated options.stream (a writable stream to write logs into). In winston 4 this option is removed; the dedicated winston.transports.Stream transport is the supported way to pipe logs into an arbitrary stream. This is also validated by throwIf('stream', 'filename', 'maxsize') which throws if stream is combined with those options.

Source

Thrown at lib/winston/transports/file.js:66

    // Setup the base stream that always gets piped to to handle buffering.
    this._stream = new PassThrough();
    this._stream.setMaxListeners(30);

    // Bind this context for listener methods.
    this._onError = this._onError.bind(this);

    if (options.filename || options.dirname) {
      throwIf('filename or dirname', 'stream');
      this._basename = this.filename = options.filename
        ? path.basename(options.filename)
        : 'winston.log';

      this.dirname = options.dirname || path.dirname(options.filename);
      this.options = options.options || { flags: 'a' };
    } else if (options.stream) {
      // eslint-disable-next-line no-console
      console.warn('options.stream will be removed in winston@4. Use winston.transports.Stream');
      throwIf('stream', 'filename', 'maxsize');
      this._dest = this._stream.pipe(this._setupStream(options.stream));
      this.dirname = path.dirname(this._dest.path);
      // We need to listen for drain events when write() returns false. This
      // can make node mad at times.
    } else {
      throw new Error('Cannot log to file without filename or stream.');
    }

    this.maxsize = options.maxsize || null;
    this.rotationFormat = options.rotationFormat || false;
    this.zippedArchive = options.zippedArchive || false;
    this.maxFiles = options.maxFiles || null;
    this.eol = (typeof options.eol === 'string') ? options.eol : os.EOL;
    this.tailable = options.tailable || false;
    this.lazy = options.lazy || false;

    // Internal state variables representing the number of files this instance

View on GitHub (pinned to ff0b79de85)

Solutions

  1. Replace with winston.transports.Stream: new winston.transports.Stream({ stream: myStream }).
  2. If writing to a file, drop stream and use options.filename (plus dirname/options) on the File transport.
  3. Ensure stream is not passed together with filename or maxsize, which throws regardless of the warning.

Example fix

// before
new winston.transports.File({ stream: process.stdout });
// after
new winston.transports.Stream({ stream: process.stdout });
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard transport options before constructing File transport
function assertNoFileStream(options) {
  if (options && 'stream' in options) {
    throw new TypeError("Use winston.transports.Stream for streams; 'stream' is removed in winston@4.");
  }
}

Type guard

function isFileStreamOptions(options) {
  return options != null && 'filename' in options && !('stream' in options);
}

Prevention

When it happens

Trigger: Creating new winston.transports.File({ stream: someWritableStream }) instead of new winston.transports.Stream({ stream: ... }). Also throws when options.stream is combined with filename or maxsize.

Common situations: Migrating winston 2.x configs where File({stream}) was the standard stream-piping pattern; combining stream with filename during partial refactors; copying pre-3.0 transport configuration.

Related errors


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