Skip to content

TypeScript SDK: route websocket errors on established connections to onDisconnect - #5707

Merged
JasonAtClockwork merged 3 commits into
clockworklabs:masterfrom
sephirith:ts-sdk-onerror-lifecycle
Sep 1, 2026
Merged

TypeScript SDK: route websocket errors on established connections to onDisconnect#5707
JasonAtClockwork merged 3 commits into
clockworklabs:masterfrom
sephirith:ts-sdk-onerror-lifecycle

Conversation

@sephirith

Copy link
Copy Markdown
Contributor

Description of Changes

Fixes #5706.

The TypeScript SDK's ws.onerror handler treats every websocket error as a connect failure: it sets isActive = false and emits connectError, even when the connection was already established. On an established connection this fires onConnectError (documented as a connect-time failure callback and commonly wired to boot-time auth recovery), silently disables the outbound send path while the socket may still be OPEN (reducer and procedure calls queue with no disconnect to trigger reconnect logic), and loses the error entirely if onclose eventually arrives, since the disconnect emit carried no error argument.

This change tracks whether the initial connection succeeded (InitialConnection received, onConnect invoked). A websocket error after that point no longer emits connectError; instead the error is recorded and the socket is closed, so the existing onclose path emits disconnect and every consumer's existing reconnect handling takes over. The recorded error is passed through to the disconnect emit, which honors the documented onDisconnect contract ("If the connection ended because of an error, the error is passed to the callback"). Errors before the initial connection succeeds emit connectError exactly as before.

API and ABI breaking changes

None. onDisconnect callbacks already accept an optional error argument (error?: Error | undefined); passing the error is additive and matches the documented behavior. Pre-connect connectError behavior is unchanged.

Expected complexity level and risk

1 - two private fields and a gate in one method. The only behavioral change is on a code path that previously produced a silently stalled connection routed to the wrong callback; it now produces a socket close, which flows through the disconnect handling every consumer already has.

Testing

  • npm test in crates/bindings-typescript passes (289 tests, 29 files).
  • prettier --check passes on the changed file.
  • Manually verified the failure mode in production (Tidefall, spacetimedb@2.7.1): a mid-session websocket error previously fired our onConnectError login-recovery path while reducer calls silently queued and no reconnect ran; with this routing the socket closes, onDisconnect fires with the error, and the client reconnects normally.

@sephirith

Copy link
Copy Markdown
Contributor Author

@bfops @JasonAtClockwork - Thanks for merging in my last PR. Another small but important one here. Could you please review and merge?

@JasonAtClockwork JasonAtClockwork left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, but it needs a small fix to ensure onDisconnect() receives the documented Error shape. It would also be good to add a small regression test for the new mid-stream error handling.

Comment thread crates/bindings-typescript/src/sdk/db_connection_impl.ts
@CLAassistant

CLAassistant commented Aug 21, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@sephirith
sephirith force-pushed the ts-sdk-onerror-lifecycle branch from 70fed09 to 3a4a906 Compare August 21, 2026 23:26

Copy link
Copy Markdown

I pulled the latest head 3a4a906 and independently verified the updated lifecycle path.

  • The focused regression test passes: 1 passed | 17 skipped.
  • Focused ESLint passes for tests/db_connection.test.ts and src/sdk/db_connection_impl.ts.
  • One check still fails locally: Prettier reports src/sdk/db_connection_impl.ts.

Command:

pnpm --dir crates/bindings-typescript exec prettier src/sdk/db_connection_impl.ts --check

Running Prettier changes only the DbConnectionImpl class declaration formatting back to the repository’s expected multiline style. The ErrorEvent normalization and new mid-stream regression test otherwise exercise the behavior I was reproducing as expected. Hope this is useful.

@bfops
bfops requested a review from JasonAtClockwork August 24, 2026 15:44

@JasonAtClockwork JasonAtClockwork left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update @sephirith!

…onDisconnect

Fixes clockworklabs#5706. ws.onerror previously emitted connectError and disabled the send path for every websocket error, even mid-session, leaving the client silently stalled with no disconnect to trigger reconnect handling. Errors on an established connection now close the socket so the onclose path emits disconnect, with the error passed through per the documented onDisconnect contract. Pre-connect errors emit connectError as before.

Also normalizes websocket errors to Error before emitting and adds a mid-stream regression test.
@sephirith
sephirith force-pushed the ts-sdk-onerror-lifecycle branch from 85f6046 to 46eeed1 Compare August 27, 2026 11:38
@sephirith

Copy link
Copy Markdown
Contributor Author

@JasonAtClockwork - Just a reminder that this one still needs to be merged in. :)

@JasonAtClockwork
JasonAtClockwork added this pull request to the merge queue Sep 1, 2026
Merged via the queue into clockworklabs:master with commit 549489e Sep 1, 2026
35 checks passed
jonahsnider Bot added a commit to jonahsnider/homebrew-tap that referenced this pull request Sep 5, 2026
Created by `brew bump`

---

Created with `brew bump-formula-pr`.<details>
  <summary>release notes</summary>
  <pre>## Features

### C# NativeAOT monomorphized dispatch

Generated C# module exports now dispatch directly to statically-known
generic entrypoints for reducers, procedures, HTTP handlers, views, and
anonymous views when building with NativeAOT-LLVM. This eliminates
virtual dispatch overhead at the module boundary and improves NativeAOT
module performance.

([#5610](<clockworklabs/SpacetimeDB#5610>))

### MCP support on Maincloud

The SpacetimeDB MCP endpoint (`/v1/mcp`) is now available on Maincloud.
You can connect AI agents and MCP-compatible tools directly to your
Maincloud databases. This release also adds cluster-aware routing so
that MCP requests sent to any node are automatically proxied to the
leader replica, along with egress tracking for MCP tool calls.

([#5849](<clockworklabs/SpacetimeDB#5849>),
[#5793](<clockworklabs/SpacetimeDB#5793>))

## Bug Fixes

### TypeScript SDK: route mid-session websocket errors to onDisconnect

The TypeScript SDK's `ws.onerror` handler previously treated every
websocket error as a connection failure, even on established
connections. This fired `onConnectError` instead of `onDisconnect`,
silently disabled the outbound send path, and left the client in a
stalled state with no reconnect. Mid-session errors now close the socket
and fire `onDisconnect` with the error, allowing existing reconnect
handling to take over.

([#5707](<clockworklabs/SpacetimeDB#5707>))

### Fix C++ auto-increment macro symbol collisions

C++ auto-increment field macros previously used `__LINE__` to generate
symbols, causing collisions when two table definitions in separate files
had an auto-increment field on the same line number. Macros now use
table and field names to guarantee unique symbols.

([#5836](<clockworklabs/SpacetimeDB#5836>))

### Fix `spacetime dev` C# complaint on macOS

The `spacetime dev` command no longer incorrectly warns about C# on
macOS when C# is not in use.

([#5867](<clockworklabs/SpacetimeDB#5867>))

## What's Changed

- Allow monomorphization for C# NativeAOT reducers, procedures, HTTP
handlers, and views in
[#5610](<clockworklabs/SpacetimeDB#5610>)
- Add MCP request routing to leader replica in
[#5849](<clockworklabs/SpacetimeDB#5849>)
- Add egress tracking for MCP requests in
[#5793](<clockworklabs/SpacetimeDB#5793>)
- Route TypeScript SDK mid-session websocket errors to onDisconnect in
[#5707](<clockworklabs/SpacetimeDB#5707>)
- Fix C++ auto-increment macro symbol collisions in
[#5836](<clockworklabs/SpacetimeDB#5836>)
- Fix `spacetime dev` C# warning on macOS in
[#5867](<clockworklabs/SpacetimeDB#5867>)

**Full Changelog**:
[v2.9.0...v2.10.0](<https://github.com/clockworklabs/SpacetimeDB/compare/v2.9.0...release/candidate/v2.10.0>)</pre>
<p>View the full release notes at <a
href="https://github.com/clockworklabs/SpacetimeDB/releases/tag/v2.10.0">https://github.com/clockworklabs/SpacetimeDB/releases/tag/v2.10.0</a>.</p>
</details>
<hr>

---------

Co-authored-by: Anka <runner@sjc22-bm210-84d28139-e2f6-4b7c-92ee-6c21afdf23c2-32D5D422D197.local>
Co-authored-by: jonahsnider[bot] <287348350+jonahsnider[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeScript SDK: ws.onerror on an established connection fires onConnectError and silently stalls the client instead of routing to onDisconnect

5 participants