pinojs/pino · error · Error
option.transport do not allow stream, please pass to option
Error message
option.transport do not allow stream, please pass to option directly. e.g. pino(transport)
What it means
This fires when opts.transport is itself a stream (a SonicBoom instance or an object with writable/_writableState). Streams must be passed directly as pino's second argument, never nested inside options.transport, which only accepts a transport descriptor (target/targets string or object) for the worker thread.
Source
Thrown at lib/tools.js:339
}
function createArgsNormalizer (defaultOptions) {
return function normalizeArgs (instance, caller, opts = {}, stream) {
// support stream as a string
if (typeof opts === 'string') {
stream = buildSafeSonicBoom({ dest: opts })
opts = {}
} else if (typeof stream === 'string') {
if (opts && opts.transport) {
throw Error('only one of option.transport or stream can be specified')
}
stream = buildSafeSonicBoom({ dest: stream })
} else if (opts instanceof SonicBoom || opts.writable || opts._writableState) {
stream = opts
opts = {}
} else if (opts.transport) {
if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) {
throw Error('option.transport do not allow stream, please pass to option directly. e.g. pino(transport)')
}
if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === 'function') {
throw Error('option.transport.targets do not allow custom level formatters')
}
let customLevels
if (opts.customLevels) {
customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels)
}
stream = transport({ caller, ...opts.transport, levels: customLevels })
}
opts = Object.assign({}, defaultOptions, opts)
opts.serializers = Object.assign(Object.create(null), defaultOptions.serializers, opts.serializers)
opts.formatters = Object.assign({}, defaultOptions.formatters, opts.formatters)
if (opts.prettyPrint) {
throw new Error('prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)')
}View on GitHub (pinned to 5aa62305c5)
Solutions
- Pass the stream as the second argument instead: pino(opts, theStream).
- Or if the stream is a destination file path, use pino.destination(...) and pass it directly: pino(opts, pino.destination('/tmp/log')).
- Or replace the stream with a real transport descriptor: pino({ transport: { target: 'pino/file', options: { destination: '/tmp/log' } } }).
- If no options besides the stream are needed, simply call pino(theStream).
Example fix
// before
const logger = pino({ transport: pino.destination('./app.log') })
// after
const logger = pino(pino.destination('./app.log')) Defensive patterns
Strategy: type-guard
Validate before calling
function validatePinoOpts(opts) {
if (opts && opts.transport && (opts.transport.writable || '_writableState' in opts.transport)) {
throw new TypeError('Do not nest a stream in opts.transport; pass it as pino(opts, stream)')
}
return true
} Type guard
const isWritableStream = (s) => s instanceof Object && (s.writable === true || s._writableState !== undefined)
Try / catch
try {
const logger = pino(opts)
} catch (err) {
if (err.message.includes('option.transport do not allow stream')) {
logger = pino(opts, opts.transport) // hoist the stream out of opts
} else throw err
} Prevention
- Remember transport only accepts { target } / { targets } descriptors or a string module path
- Pass streams (pino.destination(...), SonicBoom, net.Socket) as the second pino argument
- In TypeScript, type transport as a descriptor union so stream objects are rejected at compile time
When it happens
Trigger: Calling pino({ transport: pino.destination('/tmp/log') }) or pino({ transport: someWritableStream }).
Common situations: Mistakenly nesting an existing stream under options when refactoring from pino(stream) to an options object; misreading the transport option as 'the stream to write to'; TypeScript-less code where the intended shape wasn't enforced.
Related errors
- only one of option.transport or stream can be specified
- only one of target or targets can be specified
- option.transport.targets do not allow custom level formatter
- missing bindings for child Pino
- Levels comparison should be one of "ASC", "DESC" or "functio
AI-assisted analysis of pinojs/pino@5aa62305c5 (2026-09-02).
Data as JSON: /api/errors/6081be498db7b7b0.
Report an issue: GitHub.