pinojs/pino · error · Error
pino – redact must contain an array of strings
Error message
pino – redact must contain an array of strings
What it means
redaction's handle() normalizes its options: if given an array it treats it as paths; otherwise it reads opts.paths. When opts is an object whose paths is not an array, pino throws this message because redaction requires a list of path strings to build the censor functions.
Source
Thrown at lib/redaction.js:113
o[k] = Redact({
paths: shape[k],
censor: wrappedCensor,
serialize,
strict,
remove
})
}
return o
}, result)
}
function handle (opts) {
if (Array.isArray(opts)) {
opts = { paths: opts, censor: CENSOR }
return opts
}
let { paths, censor = CENSOR, remove } = opts
if (Array.isArray(paths) === false) { throw Error('pino – redact must contain an array of strings') }
if (remove === true) censor = undefined
return { paths, censor, remove }
}
module.exports = redaction
View on GitHub (pinned to 5aa62305c5)
Solutions
- Wrap the path(s) in an array: paths: ['req.headers.authorization'].
- Or pass the array directly as the whole redact option: redact: ['paths.here'].
- Ensure each array element is a string path (wildcards like '*.password' allowed).
- Validate/normalize config: Array.isArray(v) ? v : [v] before constructing the logger.
Example fix
// before
pino({ redact: { paths: 'req.headers.authorization' } })
// after
pino({ redact: { paths: ['req.headers.authorization'] } }) Defensive patterns
Strategy: validation
Validate before calling
function normalizeRedact(redact) {
if (Array.isArray(redact)) return redact
const paths = redact && redact.paths
if (!Array.isArray(paths)) throw new TypeError('redact.paths must be an array of strings')
return { ...redact, paths }
}
const logger = pino({ redact: normalizeRedact(cfg.redact) }) Type guard
function hasValidRedactPaths(redact) {
if (Array.isArray(redact)) return redact.every(p => typeof p === 'string')
return redact != null && Array.isArray(redact.paths) && redact.paths.every(p => typeof p === 'string')
} Try / catch
try {
logger = pino({ redact: redactCfg })
} catch (e) {
if (e.message.includes('redact must contain an array of strings')) {
logger = pino({ redact: { paths: [].concat(redactCfg && redactCfg.paths || []) } })
} else throw e
} Prevention
- Always pass paths as an array, even for a single path.
- Prefer the simple form redact: ['a.b.c'] when censor/remove options are not needed.
- Validate redact config at startup; coerce single strings to arrays before constructing pino.
- Add a schema (e.g. JSON schema/ajv) for your logging config including redact.paths as array of strings.
When it happens
Trigger: pino({ redact: { paths: 'req.headers.authorization' } }) — a string instead of an array; redact: { paths: null }; passing a Set or object-map instead of an array of strings.
Common situations: Config loaded from JSON/env where a single path was given as a plain string; users migrating from docs examples that show a bare array (redact: ['a.b']) then switching to the object form without wrapping paths in [] .
Related errors
- Levels comparison should be one of "ASC", "DESC" or "functio
- pino – redact must contain an array of strings
- unknown level ${level}
- default level:${defaultLevel} must be included in custom lev
- levels cannot be overridden
AI-assisted analysis of pinojs/pino@5aa62305c5 (2026-09-02).
Data as JSON: /api/errors/36e17b86bc1ee08e.
Report an issue: GitHub.