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

  1. Wrap the path(s) in an array: paths: ['req.headers.authorization'].
  2. Or pass the array directly as the whole redact option: redact: ['paths.here'].
  3. Ensure each array element is a string path (wildcards like '*.password' allowed).
  4. 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

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


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