Skip to content

fix(transport-webtransport): abort connection when session dies#3489

Open
paschal533 wants to merge 2 commits intolibp2p:mainfrom
paschal533:fix/webtransport-abort-on-stale-session
Open

fix(transport-webtransport): abort connection when session dies#3489
paschal533 wants to merge 2 commits intolibp2p:mainfrom
paschal533:fix/webtransport-abort-on-stale-session

Conversation

@paschal533
Copy link
Copy Markdown
Contributor

Problem

When a WebTransport session becomes invalid after a network interruption or laptop sleep/resume, connection.newStream() calls createBidirectionalStream() on the dead WebTransport object which throws:

DOMException: Failed to execute 'createBidirectionalStream' on 'WebTransport': No connection.

Three independent gaps caused the stale connection to remain in the connection manager indefinitely:

  1. muxer.ts onCreateStream() — the DOMException from createBidirectionalStream() propagated unhandled; neither the muxer nor the connection were cleaned up.
  2. muxer.ts incoming stream reader — errors from the incomingBidirectionalStreams reader were only logged; no cleanup triggered.
  3. index.ts wt.closed rejectioncleanUpWTSession() only set maConn.timeline.close = Date.now(). This never dispatches a close event on maConn, so the connection manager was never notified even when wt.closed eventually fired.

Changes

src/muxer.ts

onCreateStream() — wrap createBidirectionalStream() in try/catch. On error, call this.abort(err) (all open streams) and this.maConn.abort(err) before rethrowing. maConn.abort() triggers: sendReset()cleanUpWTSession()wt.close(), then dispatches a StreamAbortEvent ('close' event) on maConn. This propagates through Connection → upgrader → connection:close event bus → connection manager removes the entry.

Incoming stream reader — add this.abort(err) and this.maConn.abort(err) to the .catch() handler (same cleanup for the inbound path).

src/index.ts

Split .catch().finally() into .then()/.catch(). In the .catch(), call cleanUpWTSession('remote_close') first (sets closed = true to prevent a double wt.close() call via sendReset()), then maConn?.abort(err) to fire the full close event chain.

test/muxer.spec.ts (new)

Two unit tests using sinon-ts stubs:

  • onCreateStream catches DOMException and aborts maConn
  • Incoming stream reader failure aborts maConn

Closes #1982

Test plan

  • cd packages/transport-webtransport && npx aegir test -t node — both new muxer tests pass
  • npx aegir build — no TypeScript errors
  • Browser integration test (requires go-libp2p server): intentionally idle a connection and confirm that newStream() rejects cleanly and the connection is removed from the connection manager after resume

…on dies

When a WebTransport session becomes invalid (e.g. after laptop
sleep/resume), createBidirectionalStream() throws a DOMException.
Previously this error propagated unhandled and the connection was
never removed from the connection manager.

Three fixes:

- muxer.ts onCreateStream(): catch the DOMException from
  createBidirectionalStream(), then call this.abort(err) and
  this.maConn.abort(err) before rethrowing. This triggers the full
  cleanup chain: sendReset() -> cleanUpWTSession() -> wt.close(),
  followed by a StreamAbortEvent on maConn which propagates through
  Connection -> upgrader -> connection manager removal.

- muxer.ts incoming stream reader: call abort on both the muxer and
  maConn when the incomingBidirectionalStreams reader fails (same
  session-death scenario on the inbound path).

- index.ts wt.closed handler: split .catch().finally() into
  .then()/.catch() so that when wt.closed rejects, cleanUpWTSession
  is called first (sets closed=true to prevent double wt.close()), then
  maConn.abort(err) fires the close event chain.

Closes libp2p#1982
@paschal533 paschal533 requested a review from a team as a code owner May 5, 2026 12:10
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.

WebTransport throws NetworkError when creating a new stream on a (very) old connection

1 participant