{"record":{"id":"36e17b86bc1ee08e","repo":"pinojs/pino","slug":"pino-redact-must-contain-an-array-of-strings-36e17b","errorCode":null,"errorMessage":"pino – redact must contain an array of strings","messagePattern":"pino – redact must contain an array of strings","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/redaction.js","lineNumber":113,"sourceCode":"      o[k] = Redact({\n        paths: shape[k],\n        censor: wrappedCensor,\n        serialize,\n        strict,\n        remove\n      })\n    }\n    return o\n  }, result)\n}\n\nfunction handle (opts) {\n  if (Array.isArray(opts)) {\n    opts = { paths: opts, censor: CENSOR }\n    return opts\n  }\n  let { paths, censor = CENSOR, remove } = opts\n  if (Array.isArray(paths) === false) { throw Error('pino – redact must contain an array of strings') }\n  if (remove === true) censor = undefined\n\n  return { paths, censor, remove }\n}\n\nmodule.exports = redaction\n","sourceCodeStart":95,"sourceCodeEnd":120,"githubUrl":"https://github.com/pinojs/pino/blob/5aa62305c57709ebd6f6b7c328e8830eeb29b297/lib/redaction.js#L95-L120","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 [] .","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."],"exampleFix":"// before\npino({ redact: { paths: 'req.headers.authorization' } })\n// after\npino({ redact: { paths: ['req.headers.authorization'] } })","handlingStrategy":"validation","validationCode":"function normalizeRedact(redact) {\n  if (Array.isArray(redact)) return redact\n  const paths = redact && redact.paths\n  if (!Array.isArray(paths)) throw new TypeError('redact.paths must be an array of strings')\n  return { ...redact, paths }\n}\nconst logger = pino({ redact: normalizeRedact(cfg.redact) })","typeGuard":"function hasValidRedactPaths(redact) {\n  if (Array.isArray(redact)) return redact.every(p => typeof p === 'string')\n  return redact != null && Array.isArray(redact.paths) && redact.paths.every(p => typeof p === 'string')\n}","tryCatchPattern":"try {\n  logger = pino({ redact: redactCfg })\n} catch (e) {\n  if (e.message.includes('redact must contain an array of strings')) {\n    logger = pino({ redact: { paths: [].concat(redactCfg && redactCfg.paths || []) } })\n  } else throw e\n}","preventionTips":["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."],"tags":["configuration","logging","redaction"],"backgroundTag":"invalid-redact-paths","analyzedSha":"5aa62305c57709ebd6f6b7c328e8830eeb29b297","analyzedAt":"2026-09-02T22:05:21.418Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}