You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On Node 24.17.0+, every danger ci run against the GitHub API fails during DSL assembly while fetching the PR file list / diff / commits — before the Dangerfile is evaluated:
Failed to fetch GitHub pull request files: FetchError: Invalid response body while trying to fetch https://<host>/api/v3/repos/<owner>/<repo>/pulls/<n>/files?page=1&per_page=100: Premature close
at Gunzip.<anonymous> (node_modules/node-fetch/lib/index.js:400:12)
type: 'system',
errno: 'ERR_STREAM_PREMATURE_CLOSE',
code: 'ERR_STREAM_PREMATURE_CLOSE'
It is deterministic: green on Node 24.16.0, red on Node 24.17.0 for the same repo and the same Danger version.
Root cause
This is not a real decode/stream failure — it's a false positive from a Node change interacting with node-fetch@2:
node-fetch@2's fixResponseChunkedTransferBadEnding (lib/index.js:1739) only runs for responses sent as Transfer-Encoding: chunked with noContent-Length — which is exactly how the GitHub API returns gzip-encoded JSON. On socket close it decides the connection ended uncleanly via socket.listenerCount('data') > 0 (lib/index.js:1745) and throws a synthetic ERR_STREAM_PREMATURE_CLOSE (:1748). With the new idle-socket listener, that check now fires on perfectly healthy responses.
The Gunzip in the stack trace is incidental — it's just the response body stream the synthetic error gets .destroy()'d onto.
Why this needs addressing in Danger
The crashing requests (getPullRequestFiles, getPullRequestDiff, getPullRequestCommits) are issued by Danger core during DSL assembly, before the Dangerfile runs, so consumers have no seam to work around it (no request-option hook; the only fetch DI point is reserved for Peril).
node-fetch@2 is effectively frozen at 2.7.0 and won't be patched; node-fetch@3 is ESM-only and can't be require()'d by Danger.
Have Danger's fetch wrapper decline gzip negotiation (compress: false) for its API requests. The server then returns identity-encoded bodies with a Content-Length, so the chunked && !content-length branch never arms. Minimal, backwards-compatible, no dependency change, and easily reverted once a patched Node line ships or the undici migration (#1514) lands.
I'll open a PR with this change plus a regression test.
Environment
Danger
13.x (also affects 11.x / 12.x — all depend on node-fetch@^2)
Node
24.17.0+ (and the corresponding 22.x security release line)
Summary
On Node 24.17.0+, every
danger cirun against the GitHub API fails during DSL assembly while fetching the PR file list / diff / commits — before the Dangerfile is evaluated:It is deterministic: green on Node 24.16.0, red on Node 24.17.0 for the same repo and the same Danger version.
Root cause
This is not a real decode/stream failure — it's a false positive from a Node change interacting with
node-fetch@2:http.Agentso that idle keep-alive sockets in the free socket pool retain a'data'listener. See http: node-fetch throws ERR_STREAM_PREMATURE_CLOSE on keep-alive socket closures after latest security releases nodejs/node#63989 ("node-fetch throws ERR_STREAM_PREMATURE_CLOSE on keep-alive socket closures after latest security releases") and the fix http: avoid stream listeners on idle agent sockets nodejs/node#64004 ("http: avoid stream listeners on idle agent sockets").node-fetch@2'sfixResponseChunkedTransferBadEnding(lib/index.js:1739) only runs for responses sent asTransfer-Encoding: chunkedwith noContent-Length— which is exactly how the GitHub API returns gzip-encoded JSON. On socketcloseit decides the connection ended uncleanly viasocket.listenerCount('data') > 0(lib/index.js:1745) and throws a syntheticERR_STREAM_PREMATURE_CLOSE(:1748). With the new idle-socket listener, that check now fires on perfectly healthy responses.The
Gunzipin the stack trace is incidental — it's just the response body stream the synthetic error gets.destroy()'d onto.Why this needs addressing in Danger
getPullRequestFiles,getPullRequestDiff,getPullRequestCommits) are issued by Danger core during DSL assembly, before the Dangerfile runs, so consumers have no seam to work around it (no request-option hook; the only fetch DI point is reserved for Peril).node-fetch@2is effectively frozen at 2.7.0 and won't be patched;node-fetch@3is ESM-only and can't berequire()'d by Danger.Suggested fix
Have Danger's fetch wrapper decline gzip negotiation (
compress: false) for its API requests. The server then returns identity-encoded bodies with aContent-Length, so thechunked && !content-lengthbranch never arms. Minimal, backwards-compatible, no dependency change, and easily reverted once a patched Node line ships or the undici migration (#1514) lands.I'll open a PR with this change plus a regression test.
Environment
node-fetch@^2)