{"record":{"id":"1ccac2530683d7a8","repo":"pinojs/pino","slug":"stream-object-needs-to-implement-either-streamentr","errorCode":null,"errorMessage":"stream object needs to implement either StreamEntry or DestinationStream interface","messagePattern":"stream object needs to implement either StreamEntry or DestinationStream interface","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/multistream.js","lineNumber":116,"sourceCode":"  function flushSync () {\n    for (const { stream } of this.streams) {\n      if (typeof stream.flushSync === 'function') {\n        stream.flushSync()\n      }\n    }\n  }\n\n  function add (dest) {\n    if (!dest) {\n      return this\n    }\n\n    // Check that dest implements either StreamEntry or DestinationStream\n    const isStream = typeof dest.write === 'function' || dest.stream\n    const stream_ = dest.write ? dest : dest.stream\n    // This is necessary to provide a meaningful error message, otherwise it throws somewhere inside write()\n    if (!isStream) {\n      throw Error('stream object needs to implement either StreamEntry or DestinationStream interface')\n    }\n\n    const { streams, streamLevels } = this\n\n    let level\n    if (typeof dest.levelVal === 'number') {\n      level = dest.levelVal\n    } else if (typeof dest.level === 'string') {\n      level = streamLevels[dest.level]\n    } else if (typeof dest.level === 'number') {\n      level = dest.level\n    } else {\n      level = DEFAULT_INFO_LEVEL\n    }\n\n    const dest_ = {\n      stream: stream_,\n      level,","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/pinojs/pino/blob/5aa62305c57709ebd6f6b7c328e8830eeb29b297/lib/multistream.js#L98-L134","documentation":"multistream's add() requires each destination to be either a DestinationStream (has a write function) or a StreamEntry (has a .stream property). The check exists so the failure is reported here with a clear message instead of an obscure crash later inside write().","triggerScenarios":"pino.multistream([{ level: 'info' }]) passing an object that lacks both write and stream; add({ level: 'debug' }) with a plain config object; passing null/undefined-ish wrappers or a stream created incorrectly.","commonSituations":"Wrapping streams in an options-like object but forgetting the stream key; passing a filename string instead of a created stream; upgrading pino and switching from a bare stream to { level, stream } entries incorrectly.","solutions":["Pass an actual stream (e.g. fs.createWriteStream(path), process.stdout) either directly or as { stream, level }.","Check that the object you pass has .write (function) or .stream before adding.","If wrapping, set the entry's stream property: { stream: myStream, level: 'info' }.","Ensure you are not passing a string path — open the stream first with fs.createWriteStream or pino.destination."],"exampleFix":"// before\npino(pino.multistream([{ level: 'info' }])) // missing stream\n// after\nconst dest = pino.destination({ dest: './app.log', sync: false })\npino(pino.multistream([{ level: 'info', stream: dest }]))","handlingStrategy":"type-guard","validationCode":"function isUsableStream(s) {\n  return !!s && (typeof s.write === 'function' || (typeof s.stream === 'object' && s.stream !== null))\n}\nconst entries = candidates.map(c => isUsableStream(c) ? c : { stream: c, level: 'info' })","typeGuard":"function isStreamEntryOrDestination(dest) {\n  return dest != null && (\n    typeof dest.write === 'function' ||\n    (typeof dest === 'object' && dest.stream != null && typeof dest.stream.write === 'function')\n  )\n}","tryCatchPattern":"try {\n  multi.add(dest)\n} catch (e) {\n  if (e.message.includes('StreamEntry or DestinationStream')) {\n    throw new TypeError('multistream destination must have .write or .stream: got ' + typeof dest, { cause: e })\n  }\n  throw e\n}","preventionTips":["Always build destinations with pino.destination or fs.createWriteStream, never raw path strings.","For leveled entries use the { stream, level } shape with stream set to a real stream.","Validate each multistream entry with a type guard at config load time.","Prefer passing process.stdout directly rather than wrapping it in bare config objects."],"tags":["configuration","logging","streams"],"backgroundTag":"invalid-stream-interface","analyzedSha":"5aa62305c57709ebd6f6b7c328e8830eeb29b297","analyzedAt":"2026-09-02T22:05:21.418Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}