pinojs/pino · error · Error
only one of target or targets can be specified
Error message
only one of target or targets can be specified
What it means
The transport() function accepts either a single target or an array of targets, never both. lib/transport.js:215 throws when both options.target and options.targets are provided to avoid ambiguity about which stream configuration to build.
Source
Thrown at lib/transport.js:215
}
let usesMultistream = false
// Backwards compatibility
const callers = typeof caller === 'string' ? [caller] : caller
// This will be eventually modified by bundlers
const bundlerOverrides = (typeof globalThis === 'object' &&
Object.prototype.hasOwnProperty.call(globalThis, '__bundlerPathsOverrides') &&
globalThis.__bundlerPathsOverrides &&
typeof globalThis.__bundlerPathsOverrides === 'object')
? globalThis.__bundlerPathsOverrides
: Object.create(null)
let target = fullOptions.target
if (target && targets) {
throw new Error('only one of target or targets can be specified')
}
if (targets) {
target = bundlerOverrides['pino-worker'] || join(__dirname, 'worker.js')
options.targets = targets.filter(dest => dest.target).map((dest) => {
return {
...dest,
target: fixTarget(dest.target)
}
})
options.pipelines = targets.filter(dest => dest.pipeline).map((dest) => {
return dest.pipeline.map((t) => {
return {
...t,
level: dest.level, // duplicate the pipeline `level` property defined in the upper level
target: fixTarget(t.target)
}
})View on GitHub (pinned to 5aa62305c5)
Solutions
- Remove either target or targets from the transport options
- Wrap the single target as a one-element targets array: targets: [{ target: 'pino-pretty', options: {...} }]
- Choose based on a condition: use targets when you need multiple destinations, otherwise target
Example fix
// before
pino({ transport: { target: 'pino/file', targets: [{ target: 'pino-pretty' }] } });
// after
pino({ transport: { targets: [{ target: 'pino/file', options: { destination: './log' } }, { target: 'pino-pretty' }] } }); Defensive patterns
Strategy: type-guard
Validate before calling
function normalizeTransport(t = {}) {
if (t.target && t.targets) {
throw new Error('transport options accept either target or targets, not both');
}
return t;
} Type guard
function isMultiTarget(t) { return Array.isArray(t && t.targets); } Try / catch
try { logger = pino({ transport: t }); } catch (e) { if (/only one of target or targets/.test(e.message)) { logger = pino({ transport: { targets: [{ target: t.target }] } }); } else { throw e; } } Prevention
- Build transport config through a helper that merges target/targets exclusively
- Prefer the targets array form when config is dynamic
- Unit-test config merging so defaults never inject target alongside targets
When it happens
Trigger: pino({ transport: { target: 'pino-pretty', targets: [...] } }) — setting both keys on the same transport options object.
Common situations: Merging config objects where one sets target and another adds targets; programmatically building transport options with defaults that already include target.
Related errors
- missing bindings for child Pino
- unable to determine transport target for "${origin}"
- PINO_TRANSPORT_MULTI_TARGETS_LEVEL_FORMATTER
- only one of option.transport or stream can be specified
- option.transport do not allow stream, please pass to option
AI-assisted analysis of pinojs/pino@5aa62305c5 (2026-09-02).
Data as JSON: /api/errors/80489bac25419109.
Report an issue: GitHub.