Question presented to candidate: "You chained three streams together with .pipe(). One of them errors midway through. What happens to the other two, and is that a problem?"
What a strong answer should cover:
.pipe()only forwards data, not errors, between streams. If the source errors, the destination is left exactly as it was β nothing tells it to stop or clean up.- The practical consequence: file descriptors, sockets, or other resources held by the un-destroyed downstream streams can leak, because nothing closed them. This is the actual, concrete cost of the "silent" half of the problem, not an abstract inconvenience.
stream.pipeline()(available as a callback API and, more idiomatically today, as a promise viastream/promises) does two things.pipe()does not: it forwards an error from any stream in the chain to every other stream, destroying all of them, and it gives you one single place (the callback or the awaited promise) to find out the chain finished or failed β rather than needing an error listener on every individual stream.pipeline()also correctly propagates a chain's completion β the promise resolves only once the entire chain (not just the first stream) has finished, which matters for chains ending in an async destination.- The old workaround before
pipeline()existed β attaching an"error"listener to every stream in the chain and manually calling.destroy()on the others β is real code many older codebases still have, and it is exactly the boilerplatepipeline()was built to eliminate. .pipe()is not simply "wrong" or removed β it remains fine for a quick, throwaway script where a leaked resource on error genuinely does not matter. The recommendation is specific to production chains, especially ones involving file or network I/O.
Clarifying questions expected:
- "Does any stream in this chain hold an external resource β a file descriptor, a socket β that must be closed on failure?" β that is exactly the risk
.pipe()does not cover. - "Is this chain in a one-off script or in a long-running service?" β decides how much the leak risk actually matters here.
Code / implementation expected: Yes β showing the same failing chain under both .pipe() and pipeline(), with the destination's actual destroyed state, is the clearest way to make the difference concrete.