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
- On VS Code 1.128.0, open Command Palette →
Spring Initializr: Create a Gradle Project...
- Complete the prompts (language, group id, artifact id, dependencies, etc.) and choose a target folder.
- 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:
- 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.
- 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
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
vscjava.vscode-spring-initializr0.12.0Steps to Reproduce
Spring Initializr: Create a Gradle Project...Expected Behavior
The zip package downloaded from
start.spring.ioshould 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#L152never invokes its callback, so the wrappingPromiseindownloadAndUnzipnever 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 to1.7.0, depending onyauzl@2.10.0, which in turn depends onfd-slicer@~1.1.0).yauzldecompresses each zip entry through a chain of Node.js corestream/zlibpipes (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 flaggeddestroyed. This conflicts with the legacy destroy pattern used internally byfd-slicer(self.destroyed = true; self.push(null)instead of the proper_destroy()lifecycle). Once the write side hits backpressure (defaultfs.createWriteStreamhighWaterMarkis 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 containgradle/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):29b196694c, #62557)3f54c8ba32, nodejs/node#63834)This is not a one-off — durability concerns
fd-slicer's legacy destroy pattern, was structurally fixed inyauzl@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-zipitself has had no release since 2020, remains pinned to the vulnerableyauzl@^2.10.0, and a community PR to bump it toyauzl@3.x(max-mapper/extract-zip#146) was opened and abandoned.extract-zipwill not receive an upstream fix for this class of bug.Suggested Fix
Given
extract-zipis unmaintained and its dependency chain (yauzl@2.x+ legacyfd-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:extract-zipwith 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.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