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
- Pass a filename: new winston.transports.File({ filename: 'logs/app.log' }).
- If logging to an existing stream, pass stream: someWriteStream instead.
- Guard dynamic config: only construct the File transport when the filename/env var is a non-empty string.
- 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
- Check env vars like LOG_FILE at startup and fail loudly if logging config is required.
- Only construct the File transport conditionally when a filename exists.
- Watch for empty-string filenames — they are falsy and trigger this error.
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
- Cannot set ${name} and ${target} together
- Cannot make set from type other than Array of string element
- options.stream is required.
- { %s } was removed in winston@3.0.0.
- { %s } was removed in winston@3.0.0. Use a custom winston.fo
AI-assisted analysis of winstonjs/winston@ff0b79de85 (2026-08-31).
Data as JSON: /api/errors/9e8e4604ab1e2909.
Report an issue: GitHub.