pinojs/pino · error · Error
customLevels is required if useOnlyCustomLevels is set true
Error message
customLevels is required if useOnlyCustomLevels is set true
What it means
useOnlyCustomLevels: true tells Pino to recognize ONLY the levels defined in customLevels, discarding default levels. Without customLevels there would be zero levels, so Pino throws at logger creation.
Source
Thrown at pino.js:164
[stringifySafeSym]: stringifySafe,
[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 = falseView on GitHub (pinned to 5aa62305c5)
Solutions
- Add a customLevels object, e.g. customLevels: { foo: 10, bar: 20 }.
- Or remove useOnlyCustomLevels if you want default levels merged with custom ones.
- Verify the option spelling: customLevels (plural), defined as { name: number } with numbers > 0.
Example fix
// before
const logger = pino({ useOnlyCustomLevels: true })
// after
const logger = pino({ useOnlyCustomLevels: true, customLevels: { trace2: 15, debug2: 25 } }) Defensive patterns
Strategy: validation
Validate before calling
function validateCustomLevels(opts) {
if (opts && opts.useOnlyCustomLevels && !(opts.customLevels && Object.keys(opts.customLevels).length > 0)) {
throw new TypeError('useOnlyCustomLevels: true requires a non-empty customLevels map')
}
return true
} Type guard
const hasCustomLevels = (opts) => Boolean(opts && opts.customLevels && typeof opts.customLevels === 'object' && Object.keys(opts.customLevels).length > 0)
Try / catch
try {
const logger = pino(opts)
} catch (err) {
if (err.message.startsWith('customLevels is required if useOnlyCustomLevels')) {
logger = pino({ ...opts, customLevels: { info: 30, error: 50 } })
} else throw err
} Prevention
- Never set useOnlyCustomLevels without also defining customLevels
- Keep customLevels and useOnlyCustomLevels adjacent in the options object to avoid conditional omission
- Type the options object so useOnlyCustomLevels: true requires customLevels (discriminated union)
When it happens
Trigger: Calling pino({ useOnlyCustomLevels: true }) or pino({ level: 'mylevel', useOnlyCustomLevels: true }) without a customLevels map.
Common situations: Copy-pasting custom-level examples and enabling useOnlyCustomLevels before defining customLevels; enabling the flag in shared config where customLevels is conditionally provided; typos like customLevel (singular).
Understand the failure class
Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.
Related errors
- Levels comparison should be one of "ASC", "DESC" or "functio
- unknown level ${level}
- unknown level value${level}
- pino – redact must contain an array of strings
- pino: transmit option must have a send function
AI-assisted analysis of pinojs/pino@5aa62305c5 (2026-09-02).
Data as JSON: /api/errors/11840f9f4751fa14.
Report an issue: GitHub.