Skip to content

Gradle project generation hangs indefinitely on VS Code 1.128.0 (Node.js 24.17.0) due to extract-zip/Node.js core stream regression #282

Description

@tmp574

Summary

Generating a Gradle project via Spring Initializr: Create a Gradle Project... hangs indefinitely at the "Starting to unzip..." step. Maven project generation is unaffected. Confirmed reproducible on VS Code 1.128.0 (3 consecutive runs on one machine, plus independently reproduced by another person on a different machine). Confirmed NOT reproducible on VS Code 1.129.0, and never occurred on VS Code 1.127.x or earlier.

Environment

  • Extension version: vscjava.vscode-spring-initializr 0.12.0
  • Affected: VS Code 1.128.0 (bundled Node.js 24.17.0)
  • Not affected: VS Code 1.129.0 (bundled Node.js 24.18.0)
  • Not affected (previously worked fine): VS Code 1.127.x and earlier (bundled Node.js 24.14.0 and earlier) — no reports of this hang prior to the 1.128.0 update
  • OS: Windows 11 Pro, build 26200.8875

Steps to Reproduce

  1. On VS Code 1.128.0, open Command Palette → Spring Initializr: Create a Gradle Project...
  2. Complete the prompts (language, group id, artifact id, dependencies, etc.) and choose a target folder.
  3. Observe the progress notification stays on "Starting to unzip..." and never completes or errors out.

Expected Behavior

The zip package downloaded from start.spring.io should be extracted into the target folder, same as it does for Maven projects, the same as it always did on VS Code 1.127.x and earlier, and the same as it does again on VS Code 1.129.0 (bundled Node.js 24.18.0).

Actual Behavior

The extraction step at src/handler/GenerateProjectHandler.ts#L152 never invokes its callback, so the wrapping Promise in downloadAndUnzip never resolves or rejects, and the progress notification spins forever with no error shown to the user.

Root Cause

This extension pins extract-zip@^1.7.0 (resolves to 1.7.0, depending on yauzl@2.10.0, which in turn depends on fd-slicer@~1.1.0). yauzl decompresses each zip entry through a chain of Node.js core stream/zlib pipes (fs read stream → zlib.createInflateRaw() → fs.createWriteStream).

Node.js core commit 29b196694c ("stream: noop pause/resume on destroyed streams", nodejs/node#62557) shipped in Node.js 24.16.0 and made .pause()/.resume() a no-op once a stream is flagged destroyed. This conflicts with the legacy destroy pattern used internally by fd-slicer (self.destroyed = true; self.push(null) instead of the proper _destroy() lifecycle). Once the write side hits backpressure (default fs.createWriteStream highWaterMark is 64KB/65536 bytes) and the read side is paused, it can never be resumed — extraction stalls permanently for any single zip entry at or above that size. Gradle-generated projects contain gradle/wrapper/gradle-wrapper.jar, large enough as a single entry to cross this threshold; Maven-generated projects apparently do not.

Confirmed via the official changelog (CHANGELOG_V24.md):

  • 24.14.0 and earlier (bundled by VS Code 1.127.x and earlier): unaffected — predates the bug entirely
  • 24.16.0 (2026-05-21): introduces the bug (29b196694c, #62557)
  • 24.17.0 (2026-06-18): security-only release, does not include a fix — this is what VS Code 1.128.0 bundles, hence the reproduction
  • 24.18.0 'Krypton' (LTS) (2026-06-23): reverts the bug (3f54c8ba32, nodejs/node#63834)

This is not a one-off — durability concerns

  • The revert PR (#63834) removed the regression test that #62557 had added, and no new Node core test guards this specific scenario — a similar future stream-internals change could reintroduce the same failure mode undetected.
  • The same bad commit was also backported into Node.js 26.1.0 (2026-05-07) and remains unreverted as of the latest 26.5.0 (2026-07-08). Node.js 26.x is a live, currently-broken target for this exact bug — if this extension (or a future VS Code release) ever runs under Node 26.x before that line gets its own revert, the hang will recur.
  • The actual vulnerable component, fd-slicer's legacy destroy pattern, was structurally fixed in yauzl@3.3.1+ (thejoshwolfe/yauzl#170, using proper _destroy() lifecycle instead of manual flag manipulation) — a durable fix independent of Node's revert. However, extract-zip itself has had no release since 2020, remains pinned to the vulnerable yauzl@^2.10.0, and a community PR to bump it to yauzl@3.x (max-mapper/extract-zip#146) was opened and abandoned. extract-zip will not receive an upstream fix for this class of bug.

Suggested Fix

Given extract-zip is unmaintained and its dependency chain (yauzl@2.x + legacy fd-slicer) remains structurally fragile independent of this specific Node.js incident, relying on Node.js to keep tolerating it is not a durable strategy. Suggested:

  1. Replace extract-zip with a library that does not go through this fragile stream/zlib pipe chain, e.g. adm-zip (synchronous, in-memory extraction, zero dependencies, actively maintained) — a good fit given generated Spring Boot project archives are small.
  2. Add a bounded timeout around the extraction step in downloadAndUnzip (GenerateProjectHandler.ts) so that if extraction ever stalls again for any reason, the user gets an actionable error instead of an indefinitely spinning progress notification.

I'm happy to submit a PR with these changes if that's welcome.

Additional References

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions