winstonjs/winston · error · Error

Cannot log to file without filename or stream.

Error message

Cannot log to file without filename or stream.

What it means

The File transport constructor requires a write destination. If neither a valid filename nor a stream option is provided (the final else branch at line 73), there is nothing to write to, so it throws immediately. This is a fail-fast guard against a transport that could never emit logs.

Source

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

    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
    // has created and the current size (in bytes) of the current logfile.
    this._size = 0;
    this._pendingSize = 0;
    this._created = 0;
    this._drain = false;
    this._opening = false;
    this._ending = false;

View on GitHub (pinned to ff0b79de85)

Solutions

  1. Pass a filename: new winston.transports.File({ filename: 'logs/app.log' }).
  2. If logging to an existing stream, pass stream: someWriteStream instead.
  3. Guard dynamic config: only construct the File transport when the filename/env var is a non-empty string.
  4. Check for key typos (filename, not file or filepath) and that the value is non-empty.

Example fix

// before
const fileTransport = new winston.transports.File({ filename: process.env.LOG_FILE }); // LOG_FILE unset
// after
const fileTransport = process.env.LOG_FILE
  ? new winston.transports.File({ filename: process.env.LOG_FILE })
  : null;
Defensive patterns

Strategy: validation

Validate before calling

function requireFileTarget(opts = {}) {
  const hasFilename = typeof opts.filename === 'string' && opts.filename.length > 0;
  if (!hasFilename && !opts.stream) {
    throw new TypeError('File transport requires a non-empty filename or a stream');
  }
  return opts;
}

Type guard

const hasFileTarget = (o) => (typeof o?.filename === 'string' && o.filename.length > 0) || !!o?.stream;

Try / catch

try {
  fileTransport = new winston.transports.File({ filename: process.env.LOG_FILE });
} catch (err) {
  if (err.message.includes('without filename or stream')) {
    console.error('LOG_FILE is not set; skipping file transport');
    fileTransport = null;
  } else throw err;
}

Prevention

When it happens

Trigger: new winston.transports.File({}) or new winston.transports.File({ maxsize: 1024 }) without filename/stream; filename present but falsy (empty string ''), or filename nested under the wrong key after a config refactor.

Common situations: Environment-driven config where LOG_FILE is unset/empty so filename ends up undefined; building transports conditionally and falling through to File with no options; typos like filepath instead of filename.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


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