forcedotcom / forcedotcom/cli

Unhandled `SocketError: other side closed` from undici HTTP/2 client crashes long-running data commands

Open
#3,622 6 comments 0 reactions 0 assignees View on GitHub
bug investigating validated
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.