WebSocket events fire synchronously during close() instead of asynchronously
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 7.7k
- Forks
- 879
- Avg merge
- 2d 16h
- Merged PRs (30d)
- 68
Description
Bug Description
When close() is called on a WebSocket in the CONNECTING state, the error and close events fire synchronously during the close() call, rather than being queued to fire asynchronously after close() returns.
Reproducible By
const { WebSocket } = require('undici');
const ws = new WebSocket('wss://echo.websocket.events/');
let closeReturned = false;
ws.addEventListener('error', () => {
console.log('error event fired, closeReturned =', closeReturned);
});
ws.addEventListener('close', () => {
console.log('close event fired, closeReturned =', closeReturned);
process.exit(0);
});
console.log('Calling close()...');
ws.close();
closeReturned = true;
console.log('close() returned, closeReturned =', closeReturned);
setTimeout(() => {
console.log('Timeout - no events fired');
process.exit(1);
}, 5000);
Expected Behavior
Calling close()...
close() returned, closeReturned = true
error event fired, closeReturned = true
close event fired, closeReturned = true
See: https://jsbin.com/butegexadi/edit?html,js,output
This follows from the "queue a task" steps in in the spec: https://websockets.spec.whatwg.org/#:~:text=cleanly%2C-,the%20user%20agent%20must%20queue%20a%20task
Relevant WPTs:
- https://github.com/web-platform-tests/wpt/blob/master/websockets/interfaces/WebSocket/close/close-connecting.html
- https://github.com/web-platform-tests/wpt/blob/master/websockets/interfaces/WebSocket/close/close-connecting-async.any.js
Logs & Screenshots
Actual behavior:
Calling close()...
error event fired, closeReturned = false
close event fired, closeReturned = false
Environment
- Node v25.2.1
- undici 7.18.2
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the WebSocket.close() entry point and compare its CONNECTING-state behavior with the specification's queue-a-task requirement. Run the referenced WPTs, websockets/interfaces/WebSocket/close/close-connecting.html and close-connecting-async.any.js, and confirm that error and close events fire only after close() returns.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 64/100