pinojs/pino · error · Error
default level:${defaultLevel} must be included in custom lev
Error message
default level:${defaultLevel} must be included in custom levels What it means
assertDefaultLevelFound validates that the configured defaultLevel appears among the allowed level values: the customLevels values, plus (unless useOnlyCustomLevels is set) the default numeric levels, plus Infinity (silent). When defaultLevel is not found in that numeric set, pino throws because the logger would start at a level it cannot compare against.
Source
Thrown at lib/levels.js:183
customNums
)
const values = Object.assign(
Object.create(Object.prototype, { silent: { value: Infinity } }),
useOnlyCustomLevels ? null : DEFAULT_LEVELS,
customLevels
)
return { labels, values }
}
function assertDefaultLevelFound (defaultLevel, customLevels, useOnlyCustomLevels) {
if (typeof defaultLevel === 'number') {
const values = [].concat(
Object.keys(customLevels || {}).map(key => customLevels[key]),
useOnlyCustomLevels ? [] : Object.keys(nums).map(level => +level),
Infinity
)
if (!values.includes(defaultLevel)) {
throw Error(`default level:${defaultLevel} must be included in custom levels`)
}
return
}
const labels = Object.assign(
Object.create(Object.prototype, { silent: { value: Infinity } }),
useOnlyCustomLevels ? null : DEFAULT_LEVELS,
customLevels
)
if (!(defaultLevel in labels)) {
throw Error(`default level:${defaultLevel} must be included in custom levels`)
}
}
function assertNoLevelCollisions (levels, customLevels) {
const { labels, values } = levels
for (const k in customLevels) {
if (k in values) {View on GitHub (pinned to 5aa62305c5)
Solutions
- Add the default level to customLevels (e.g. customLevels: { info: 30, foo: 35 }) when useOnlyCustomLevels is true.
- Remove useOnlyCustomLevels: true so default pino levels remain available.
- Set defaultLevel explicitly to one of the custom level names.
- Verify the defaultLevel value/number matches one of the registered level values.
Example fix
// before
const logger = pino({ customLevels: { trace2: 15 }, useOnlyCustomLevels: true })
// after
const logger = pino({
customLevels: { trace2: 15, info: 30 },
defaultLevel: 'info',
useOnlyCustomLevels: true
}) Defensive patterns
Strategy: validation
Validate before calling
function assertCustomLevelsConfig(opts) {
const { customLevels = {}, useOnlyCustomLevels, level = 'info', defaultLevel = level } = opts
const numeric = Object.values(customLevels)
const ok = useOnlyCustomLevels
? numeric.includes(defaultLevel)
: true
if (!ok) throw new Error(`defaultLevel ${defaultLevel} missing from customLevels`)
} Type guard
function hasValidDefaultLevel(opts) {
const customLevels = opts.customLevels || {}
const defaultLevel = opts.defaultLevel || opts.level || 'info'
return !opts.useOnlyCustomLevels || Object.values(customLevels).includes(defaultLevel)
} Try / catch
try {
logger = pino(opts)
} catch (e) {
if (e.message.includes('must be included in custom levels')) {
throw new Error(`config error: defaultLevel '${opts.defaultLevel}' not in customLevels`, { cause: e })
}
throw e
} Prevention
- When useOnlyCustomLevels is true, always include the default level in customLevels.
- Set defaultLevel explicitly alongside useOnlyCustomLevels.
- Unit-test logger construction with the production config object.
- Avoid mixing default pino levels with useOnlyCustomLevels.
When it happens
Trigger: pino({ customLevels: { foo: 35 }, useOnlyCustomLevels: true }) — default level 'info' (30) is excluded because only custom levels are allowed; pino({ defaultLevel: 'warn', customLevels: { foo: 35 }, useOnlyCustomLevels: true }) without 'warn' in customLevels.
Common situations: Setting useOnlyCustomLevels: true but forgetting the defaultLevel must itself be a custom level; copying a config snippet with custom levels into a codebase that relies on the default 'info' level.
Related errors
- Levels comparison should be one of "ASC", "DESC" or "functio
- unknown level ${level}
- levels cannot be overridden
- pre-existing level values cannot be used for new levels
- stream object needs to implement either StreamEntry or Desti
AI-assisted analysis of pinojs/pino@5aa62305c5 (2026-09-02).
Data as JSON: /api/errors/608b61a7eeb4a52e.
Report an issue: GitHub.