Skip to content

fix: destroy read streams to prevent file descriptor leaks#16002

Merged
ematipico merged 5 commits into
withastro:mainfrom
buley:fix/stream-fd-leaks
Mar 24, 2026
Merged

fix: destroy read streams to prevent file descriptor leaks#16002
ematipico merged 5 commits into
withastro:mainfrom
buley:fix/stream-fd-leaks

Conversation

@buley

@buley buley commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Two createReadStream() file descriptor leaks found via static analysis of the control flow graph:

1. packages/integrations/partytown/src/sirv.ts:129

fs.createReadStream(file, opts).pipe(res) leaks the file descriptor when the HTTP response is closed prematurely (e.g. client disconnect, timeout). Node's .pipe() does not automatically destroy the source stream when the destination closes.

Fix: Captured the stream reference and added res.on('close', () => stream.destroy()).

2. packages/integrations/node/src/serve-app.ts:24

createReadStream(fullPath) in readErrorPageFromDisk() was never destroyed in the catch block. If the stream partially opened before the error event fired (e.g. permission change between open and error), the fd leaked across retry iterations as the loop tries the next file path pattern.

Fix: Moved stream declaration outside try so it can be destroyed in catch via stream?.destroy().

Test Plan

  • Both fixes only affect cleanup paths and do not change normal control flow
  • Manual: serve a large static file via partytown integration, disconnect mid-download, verify no leaked fds with lsof -p <pid>

sirv.ts: createReadStream().pipe(res) leaked the file descriptor when
the HTTP response was closed prematurely (e.g. client disconnect). The
pipe does not automatically destroy the source stream when the
destination closes. Added res.on('close') handler to destroy the stream.

serve-app.ts: createReadStream() in readErrorPageFromDisk() was never
destroyed in the catch block. If the stream partially opened before the
error event fired (e.g. permission denied after open), the fd leaked
across retry iterations. Moved stream declaration outside try so it can
be destroyed in catch.
@changeset-bot

changeset-bot Bot commented Mar 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 63a49d3

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the pkg: integration Related to any renderer integration (scope) label Mar 20, 2026

@ematipico ematipico left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Changeset is missing

Comment thread .changeset/fix-stream-leaks.md Outdated
"astro": patch
---

fix: destroy read streams to prevent file descriptor leaks

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please follow the contribution guide. Here's some tips for a good changeset https://contribute.docs.astro.build/docs-for-code-changes/changesets/#tips-and-examples

…e description per contribution guide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@buley

buley commented Mar 23, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the review and the pointer to the contribution guide -- I appreciate you taking the time. Apologies for the rough changeset on the first pass.

I've updated it to scope the patch to @astrojs/node and @astrojs/partytown (the actual affected packages rather than core astro), and rewrote the description to be user-facing and start with a present-tense verb per the guide's format.

I'll keep the changeset conventions in mind for future contributions -- scope to the right packages, write from the user's perspective, and drop conventional-commit prefixes from the description.

@ematipico ematipico merged commit 846f27f into withastro:main Mar 24, 2026
21 checks passed
@astrobot-houston astrobot-houston mentioned this pull request Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: integration Related to any renderer integration (scope)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants