Repository navigation
test_writing_in_recv_events_fails fails in freethreaded mode #1696
Description
Hi all,
As part of the RISE project, we are building, testing, and publishing riscv64 wheels for a number of popular Python packages, including websockets. We are currently publishing wheels for versions 14.1, 14.2, 15.0, and 15.0.1 (see: https://riseproject.gitlab.io/python/wheel_builder/packages/websockets.html).
Our goal is to upstream this work by submitting a pull request to add native riscv64 support directly to this repository. Before doing so, we want to ensure that the build and test process works correctly and that the resulting wheels behave as expected.
While building and testing the latest release, we encountered a test failure specifically when running the test suite against the Python 3.14t wheels. We would like to report this issue and better understand whether it is a known limitation, a riscv64-specific problem, or something we should address as part of the upstreaming effort.
ERROR: test_writing_in_recv_events_fails (tests.sync.test_connection.ClientConnectionTests.test_writing_in_recv_events_fails)
Error when responding to incoming frames is correctly reported.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/project/tests/sync/test_connection.py", line 961, in test_writing_in_recv_events_fails
self.remote_connection.ping()
~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/project/.tox/py/lib/python3.14t/site-packages/websockets/sync/connection.py", line 652, in ping
with self.send_context():
~~~~~~~~~~~~~~~~~^^
File "/opt/_internal/cpython-3.14.2-nogil/lib/python3.14t/contextlib.py", line 141, in __enter__
return next(self.gen)
File "/project/.tox/py/lib/python3.14t/site-packages/websockets/sync/connection.py", line 1020, in send_context
raise self.protocol.close_exc from original_exc
websockets.exceptions.ConnectionClosedError: no close frame received or sent
======================================================================
ERROR: test_writing_in_recv_events_fails (tests.sync.test_connection.ServerConnectionTests.test_writing_in_recv_events_fails)
Error when responding to incoming frames is correctly reported.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/project/tests/sync/test_connection.py", line 961, in test_writing_in_recv_events_fails
self.remote_connection.ping()
~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/project/.tox/py/lib/python3.14t/site-packages/websockets/sync/connection.py", line 652, in ping
with self.send_context():
~~~~~~~~~~~~~~~~~^^
File "/opt/_internal/cpython-3.14.2-nogil/lib/python3.14t/contextlib.py", line 141, in __enter__
return next(self.gen)
File "/project/.tox/py/lib/python3.14t/site-packages/websockets/sync/connection.py", line 1020, in send_context
raise self.protocol.close_exc from original_exc
websockets.exceptions.ConnectionClosedError: no close frame received or sent
----------------------------------------------------------------------
Ran 1959 tests in 111.028s
FAILED (errors=2, skipped=53)
Full log is available here: https://gitlab.com/riseproject/python/websockets/-/jobs/12860760616
I found another issue about a race condition that may or may not be related #1596. I opened a new issue since I feel like it's more free threaded related in my case.
Activity
aaugustin commentedon Feb 9, 2026
This is an extremely defensive test for an edge case that I don't even know if it is possible at all — getting the socket closed for writing by "something else" while it's still open for reading. I'm not really worried if that test fails.
From the documentation:
aaugustin commentedon Feb 9, 2026
The error you're seeing suggests that the socket is also closed for reading in addition to being closed for writing after
socket.shutdown(SHUT_WR). That's unexpected; the socket implementation on riscv64 should support half-closes.aaugustin commentedon Feb 9, 2026
There's only two threads involved in this test, one of them being the background thread that every websockets connection runs to deal automatically with control frames in the background, and I'm not seeing why free threading would cause this issue.
aaugustin commentedon Feb 9, 2026
Overall sockets in free-threaded Python don't look super robust yet e.g. here's another spurious failure that happens only on free-threaded Python.
aaugustin commentedon Feb 9, 2026
I don't have access to a RISC-V platform and I'm not super interested in debugging why this tests that works on all mainstream platform fails on RISC-V. I don't think it reveals a substantial problem with websockets on RISC-V anyway.
The most straightforward solution is simply not to run the tests. (You aren't running all the tests in the repository anyway!)
justeph commentedon Feb 10, 2026
Hi @aaugustin , thank you for detailed explanations! We will skip tests then.
Would you be open to PR adding riscv-64 support? I can open one if you are open to it.
aaugustin commentedon Feb 10, 2026
What would that mean in practice? Just enabling more builds in cibuildwheel?
justeph commentedon Feb 10, 2026
Yes
aaugustin commentedon Feb 11, 2026
I'm OK with building wheels for everything that's well supported by cibuildwheel and can be done on GitHub Actions without additional infrastructure.
While we're there, I think we should do it not just for RISC-V but also for all other platforms with similar stability / popularity. It should be a small config change.
PR welcome! :-)
justeph commentedon Feb 11, 2026
Hi @aaugustin I opened a merge request adding:
which are the architectures the most commonly built on various other projects. See #1697.
On my fork, the job takes 57 min to succeed. Maybe it's time to rework a bit the workflow to use matrix build?
aaugustin commentedon Feb 11, 2026
Thank you, that's super useful!
You mention running the job on your fork. Did you do this with the GitHub Action and, if yes, can you share a link to the build log? I'd just like to see it working before merging.
If not, I'll do that — I'll just need to push your branch to this repo and trigger manually the GitHub action (which build but doesn't upload to PyPI when run on a branch).
Taking 1h isn't a concern for me, given the release frequency on this project. GitHub Actions gives us 6 hours.
justeph commentedon Feb 11, 2026
https://github.com/justeph/websockets/actions/runs/21903021333 Here is the link of the run. There is a revertme commit on top, to make sure workflow start on branch push ;)
aaugustin commentedon Feb 11, 2026
Perfect, I'll merge (and add a quick line to the changelog) tonight.
clawdney commentedon Mar 8, 2026
Hi! I'm interested in helping with this. Could you share more context about the use case?
aaugustin commentedon Mar 8, 2026
Actually this issue is resolved already, I just forgot to close it. It looks like clawdney is an AI bot and it is not being helpful.