Summary
Since @jsforce/jsforce-node moved to undici 8.x, all Salesforce API traffic negotiates HTTP/2 by default (undici 8 changed the default of allowH2 from false to true). When Salesforce closes the HTTP/2 connection during a long-running command (idle timeout / GOAWAY mid-import), the resulting socket error is emitted as an unhandled 'error' event and the entire Node process crashes. Long sf data import tree runs cannot complete.
Steps To Reproduce
sf data import tree --plan <plan.json> with a large plan (~51,000 records across 7 sObjects, roughly a 20-minute import) against a sandbox.
- Partway through the import (observed anywhere from seconds to ~12 minutes in), the process crashes.
Because the crash is an unhandled exception, --json produces no output at all — the command dies silently from a script's perspective, with only the Node crash dump on stderr.
Actual result
node:events:486
throw er; // Unhandled 'error' event
^
SocketError: other side closed
at TLSSocket.onHttp2SocketEnd (...\@salesforce\cli\node_modules\@jsforce\jsforce-node\node_modules\undici\lib\dispatcher\client-h2.js:602:22)
at TLSSocket.emit (node:events:520:35)
at endReadableNT (node:internal/streams/readable:1701:12)
at process.processTicksAndRejections (node:internal/process/task_queues:90:21)
Emitted 'error' event on ClientHttp2Stream instance at:
at emitErrorNT (node:internal/streams/destroy:170:8)
at emitErrorCloseNT (node:internal/streams/destroy:129:3)
at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
code: 'UND_ERR_SOCKET',
...
}
Expected result
The import completes, or at minimum the connection-closed error is caught and surfaced as a normal command error (ideally retried, since it is a transient transport condition).
Analysis
- undici 8 enables HTTP/2 by default:
lib/core/connect.js — allowH2 = allowH2 != null ? allowH2 : true. undici 7 defaulted to false.
@jsforce/jsforce-node (3.10.18/3.10.19, dependency undici: ^8.5.0) never passes allowH2 and does not handle the 'error' event undici's h2 client emits when the server closes the connection, so the error escapes to the process level.
- Confirmed by workaround: patching the bundled undici to
allowH2 = false (forcing HTTP/1.1) makes the identical 51k-record import complete cleanly, first try.
- Note: pinning an older CLI version does not avoid this, because npm re-resolves jsforce-node's
undici ^8.5.0 range at install time.
Suggested fix
Either pass allowH2: false in jsforce-node's undici dispatcher options until h2 error handling is robust, or attach an error handler for UND_ERR_SOCKET on h2 streams and retry/surface it as a request error. (Likely belongs in jsforce/jsforce — filing here first since sf data import tree is the user-facing failure.)
System Information
- Shell: PowerShell 7 / Git Bash
- OS: Windows 11 Home 10.0.26200
sf --version: @salesforce/cli/2.146.3 win32-x64 node-v24.10.0 (also reproduced on a fresh npm install of 2.142.6, which resolves the same jsforce-node/undici versions)
@jsforce/jsforce-node: 3.10.19 (2.146.3) / 3.10.18 (2.142.6), both with undici 8.5.0
- Node: 24.10.0, npm 11.6.1
Summary
Since
@jsforce/jsforce-nodemoved to undici 8.x, all Salesforce API traffic negotiates HTTP/2 by default (undici 8 changed the default ofallowH2fromfalsetotrue). When Salesforce closes the HTTP/2 connection during a long-running command (idle timeout / GOAWAY mid-import), the resulting socket error is emitted as an unhandled'error'event and the entire Node process crashes. Longsf data import treeruns cannot complete.Steps To Reproduce
sf data import tree --plan <plan.json>with a large plan (~51,000 records across 7 sObjects, roughly a 20-minute import) against a sandbox.Because the crash is an unhandled exception,
--jsonproduces no output at all — the command dies silently from a script's perspective, with only the Node crash dump on stderr.Actual result
Expected result
The import completes, or at minimum the connection-closed error is caught and surfaced as a normal command error (ideally retried, since it is a transient transport condition).
Analysis
lib/core/connect.js—allowH2 = allowH2 != null ? allowH2 : true. undici 7 defaulted tofalse.@jsforce/jsforce-node(3.10.18/3.10.19, dependencyundici: ^8.5.0) never passesallowH2and does not handle the'error'event undici's h2 client emits when the server closes the connection, so the error escapes to the process level.allowH2 = false(forcing HTTP/1.1) makes the identical 51k-record import complete cleanly, first try.undici ^8.5.0range at install time.Suggested fix
Either pass
allowH2: falsein jsforce-node's undici dispatcher options until h2 error handling is robust, or attach an error handler forUND_ERR_SOCKETon h2 streams and retry/surface it as a request error. (Likely belongs in jsforce/jsforce — filing here first sincesf data import treeis the user-facing failure.)System Information
sf --version:@salesforce/cli/2.146.3 win32-x64 node-v24.10.0(also reproduced on a fresh npm install of 2.142.6, which resolves the same jsforce-node/undici versions)@jsforce/jsforce-node: 3.10.19 (2.146.3) / 3.10.18 (2.142.6), both with undici 8.5.0