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
- Pass a string: msgPrefix: 'PID ' + pid or String(template) for dynamic values.
- Coerce with String(opts.msgPrefix) before constructing options if the source may be non-string.
- Fix quoting in config files so the value parses as a string.
- 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
- Always pass msgPrefix as a string literal or String(...) coerced value
- Quote msgPrefix values in YAML/JSON configs so numbers stay strings
- Validate option types centrally before constructing loggers in wrapper modules
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
- Unknown mixin type "${typeof mixin}" - expected "function"
- Levels comparison should be one of "ASC", "DESC" or "functio
- only one of option.transport or stream can be specified
- option.transport do not allow stream, please pass to option
- option.transport.targets do not allow custom level formatter
AI-assisted analysis of pinojs/pino@5aa62305c5 (2026-09-02).
Data as JSON: /api/errors/3314268f258185ed.
Report an issue: GitHub.