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

  1. Remove either target or targets from the transport options
  2. Wrap the single target as a one-element targets array: targets: [{ target: 'pino-pretty', options: {...} }]
  3. 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

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


AI-assisted analysis of pinojs/pino@5aa62305c5 (2026-09-02). Data as JSON: /api/errors/80489bac25419109. Report an issue: GitHub.