Unhandled `SocketError: other side closed` from undici HTTP/2 client crashes long-running data commands
- Dominant language
- No language data
- Stars
- 571
- Forks
- 80
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 3
Description
# 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
1. `sf data import tree --plan ` with a large plan (~51,000 records across 7 sObjects, roughly a 20-minute import) against a sandbox.
2. 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
Contributor guide
Research direction
Start with the `sf data import tree` command and trace its Salesforce HTTP traffic into `@jsforce/jsforce-node`, then inspect the undici references in `lib/core/connect.js`. Reproduce with the large plan described in the issue and observe the HTTP/2 connection-close path. Done means the import completes or the connection error is surfaced as a normal command error instead of crashing the Node process.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- cli, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100