pinojs/pino · error · Error

Unknown msgPrefix type "${typeof msgPrefix}" - expected "str

Error message

Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"

What it means

The msgPrefix option, prepended to every log message, must be a string. If opts.msgPrefix is truthy but of another type (number, object, etc.), Pino throws with the encountered typeof. Fails at logger creation time.

Source

Thrown at pino.js:166

  })

  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 string: msgPrefix: 'PID ' + pid or String(template) for dynamic values.
  2. Coerce with String(opts.msgPrefix) before constructing options if the source may be non-string.
  3. Fix quoting in config files so the value parses as a string.
  4. Validate typeof opts.msgPrefix === 'string' in wrapper code before calling pino.

Example fix

// before
const logger = pino({ msgPrefix: 42 })
// after
const logger = pino({ msgPrefix: 'worker 42: ' })
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

const hasStringMsgPrefix = (opts) => !opts.msgPrefix || typeof opts.msgPrefix === 'string'

Try / catch

try {
  const logger = pino(opts)
} catch (err) {
  if (err.message.startsWith('Unknown msgPrefix type')) {
    logger = pino({ ...opts, msgPrefix: String(opts.msgPrefix) })
  } else throw err
}

Prevention

When it happens

Trigger: pino({ msgPrefix: 123 }) or msgPrefix: someObject/array; interpolation mistakes like msgPrefix: `[worker] ${id}.` producing a non-string; config from JSON/YAML where the value wasn't quoted/parsed as a string.

Common situations: Copy-paste edits changing a string prefix to a template/object; build tooling or env substitution injecting a non-string (e.g. numeric port used as prefix); YAML parsing "123" as a number.

Related errors


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