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.

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.

Appendix: 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)