pinojs/pino · error · Error

Unknown mixin type "${typeof mixin}" - expected "function"

Error message

Unknown mixin type "${typeof mixin}" - expected "function"

What it means

The mixin option must be a function that returns an object merged into each log line. If opts.mixin is truthy but not a function, Pino throws with the actual typeof found. This fails fast at logger creation rather than per-log-call.

Source

Thrown at pino.js:165

    [formattersSym]: allFormatters
  })

  let chindings = ''
  if (base !== null) {
    if (name === undefined) {
      chindings = coreChindings(base)
    } else {
      chindings = coreChindings(Object.assign({}, base, { name }))
    }
  }

  const time = (timestamp instanceof Function)
    ? timestamp
    : (timestamp ? epochTime : nullTime)
  const timeSliceIndex = time().indexOf(':') + 1

  if (useOnlyCustomLevels && !customLevels) throw Error('customLevels is required if useOnlyCustomLevels is set true')
  if (mixin && typeof mixin !== 'function') throw Error(`Unknown mixin type "${typeof mixin}" - expected "function"`)
  if (msgPrefix && typeof msgPrefix !== 'string') throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`)

  assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels)
  const levels = mappings(customLevels, useOnlyCustomLevels)

  if (stream && stream[transportUsesMultistreamSym] === true) {
    let sampleLabel = typeof level === 'string' ? level : undefined
    if (!sampleLabel || levels[sampleLabel] === undefined) {
      sampleLabel = Object.keys(levels)[0]
    }
    const sampleNumber = levels[sampleLabel]
    let ok = false
    try {
      const formatted = formatters.level(sampleLabel, sampleNumber)
      ok = formatted && typeof formatted === 'object' && formatted.level === sampleNumber
    } catch {
      ok = false
    }

View on GitHub (pinned to 5aa62305c5)

Solutions

  1. Pass a function: mixin: () => ({ ... }) or mixin: (context) => ({ ...context }).
  2. If the mixin is generated, pass the factory's returned function, not an intermediate object.
  3. If options come from config files, re-attach functions in code after loading the config.
  4. Check typeof opts.mixin === 'function' before calling pino in wrapper code.

Example fix

// before
const logger = pino({ mixin: { requestId: 'abc' } })
// after
const logger = pino({ mixin: () => ({ requestId: 'abc' }) })
Defensive patterns

Strategy: type-guard

Validate before calling

function validateMixin(opts) {
  if (opts && opts.mixin && typeof opts.mixin !== 'function') {
    throw new TypeError(`mixin must be a function, got ${typeof opts.mixin}`)
  }
  return true
}

Type guard

const isMixinFn = (opts) => !opts.mixin || typeof opts.mixin === 'function'

Try / catch

try {
  const logger = pino(opts)
} catch (err) {
  if (err.message.startsWith('Unknown mixin type')) {
    logger = pino({ ...opts, mixin: undefined }) // or wrap: mixin: () => opts.mixin
  } else throw err
}

Prevention

When it happens

Trigger: pino({ mixin: someObject }) or mixin set to a string/number/boolean; passing the result of calling the mixin (mixin: myMixin()) instead of the function itself; config deserialized from JSON where functions can't survive.

Common situations: Loading logger options from JSON/YAML config files (functions lost); wrapping mistakes like mixin: mixinFactory() returning an object; typos assigning an object where a callback is expected.

Related errors


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