8000 JS: new `Quality` query - Unhandled errors in `.pipe()` chain by Napalys · Pull Request #19544 · github/codeql · GitHub
[go: up one dir, main page]

Skip to content

JS: new Quality query - Unhandled errors in .pipe() chain #19544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 38 commits into
base: main
Choose a base branch
from

Conversation

Napalys
Copy link
Contributor
@Napalys Napalys commented May 20, 2025

This pull request adds a new quality query for JavaScript. This query checks for unhandled errors in the .pipe() chain of Node.js streams, helping to ensure that potential stream errors are not missed and applications remain robust.

@github-actions github-actions bot added the JS label May 20, 2025
@Napalys Napalys force-pushed the js/quality/stream_pipe branch 2 times, most recently from 26f0aeb to 21aa9d1 Compare May 21, 2025 16:15
@Napalys Napalys force-pushed the js/quality/stream_pipe branch from 21aa9d1 to b104871 Compare May 22, 2025 10:43
@Napalys Napalys force-pushed the js/quality/stream_pipe branch from 1fba9e0 to b10a948 Compare May 22, 2025 16:50
Copy link
Contributor
github-actions bot commented May 23, 2025

QHelp previews:

javascript/ql/src/Quality/UnhandledErrorInStreamPipeline.qhelp

Unhandled error in stream pipeline

In Node.js, calling the pipe() method on a stream without proper error handling can lead to unexplained failures, where errors are dropped and not propagated downstream. This can result in unwanted behavior and make debugging difficult. To reliably handle all errors, every stream in the pipeline must have an error handler registered.

Recommendation

Instead of using pipe() with manual error handling, prefer using the pipeline function from the Node.js stream module. The pipeline function automatically handles errors and ensures proper cleanup of resources. This approach is more robust and eliminates the risk of forgetting to handle errors.

If you must use pipe(), always attach an error handler to the source stream using methods like on('error', handler) to ensure that any errors emitted by the input stream are properly handled. When multiple pipe() calls are chained, an error handler should be attached before each step of the pipeline.

Example

The following code snippet demonstrates a problematic usage of the pipe() method without error handling:

const fs = require('fs');
const source = fs.createReadStream('source.txt');
const destination = fs.createWriteStream('destination.txt');

// Bad: Only destination has error handling, source errors are unhandled
source.pipe(destination).on('error', (err) => {
  console.error('Destination error:', err);
});

A better approach is to use the pipeline function, which automatically handles errors:

const { pipeline } = require('stream');
const fs = require('fs');
const source = fs.createReadStream('source.txt');
const destination = fs.createWriteStream('destination.txt');

// Good: Using pipeline for automatic error handling
pipeline(
  source,
  destination,
  (err) => {
    if (err) {
      console.error('Pipeline failed:', err);
    } else {
      console.log('Pipeline succeeded');
    }
  }
);

Alternatively, if you need to use pipe(), make sure to add error handling:

const fs = require('fs');
const source = fs.createReadStream('source.txt');
const destination = fs.createWriteStream('destination.txt');

// Alternative Good: Manual error handling with pipe()
source.on('error', (err) => {
  console.error('Source stream error:', err);
  destination.destroy(err);
});

destination.on('error', (err) => {
  console.error('Destination stream error:', err);
  source.destroy(err);
});

source.pipe(destination);

References

@Napalys Napalys added the no-change-note-required This PR does not need a change note label May 26, 2025
@Napalys Napalys marked this pull request as ready for review June 2, 2025 11:59
@Napalys Napalys requested a review from a team as a code owner June 2, 2025 11:59
Copy link
Contributor
@asgerf asgerf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work so far! 👍

Napalys and others added 5 commits June 2, 2025 17:40
Co-authored-by: Asger F <asgerf@github.com>
Co-authored-by: Asger F <asgerf@github.com>
Co-authored-by: Asger F <asgerf@github.com>
Co-authored-by: Asger F <asgerf@github.com>
Co-authored-by: Asger F <asgerf@github.com>
@Napalys Napalys force-pushed the js/quality/stream_pipe branch from 8e95d06 to d43695c Compare June 2, 2025 15:52
Napalys and others added 3 commits June 2, 2025 17:53
Co-authored-by: Asger F <asgerf@github.com>
Address comments

Co-Authored-By: Asger F <316427+asgerf@users.noreply.github.com>
@Napalys Napalys requested a review from asgerf June 3, 2025 06:36
Copy link
Contributor
@asgerf asgerf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few more comments

Comment on lines 2 to 5
* @id js/nodejs-stream-pipe-without-error-handling
* @name Node.js stream pipe without error handling
* @description Calling `pipe()` on a stream without error handling will drop errors coming from the input stream
* @kind problem
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @id js/nodejs-stream-pipe-without-error-handling
* @name Node.js stream pipe without error handling
* @description Calling `pipe()` on a stream without error handling will drop errors coming from the input stream
* @kind problem
* @id js/unhandled-error-in-stream-pipeline
* @name Unhandled error in stream pipeline
* @description Calling `pipe()` on a stream without error handling will drop errors coming from the input stream
* @kind problem
  • I think we should leave out nodejs from the query name and ID. It might grow in scope to cover other kinds of streams.
  • "Without error handling" sounds a bit off, since there is some error handling, it's just that some of the errors slip through.

Also, if you agree with the query name and ID change, could you rename the .ql files to match afterwards?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes a lot of sense to me! Changed it here 8521c53, there was a small side effect in expected files due to the merge, but it was expected.

Napalys and others added 3 commits June 3, 2025 13:43
Co-authored-by: Asger F <asgerf@github.com>
As a side effect of merge `security-and-quality` does not contain anymore related new query.

Co-Authored-By: Asger F <316427
EE99
+asgerf@users.noreply.github.com>
@@ -1,2 +1,2 @@
query: Quality/UnhandledStreamPipe.ql
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also rename the test folder.

And rename the .qlref file to UnhandledErrorInStreamPipeline.qlref as per convention.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed here 8521c53

Co-Authored-By: Asger F <316427+asgerf@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation JS no-change-note-required This PR does not need a change note
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0