Skip to content

Backport ipykernel's shell channel wedge fix for ipykernel 7.0 to 7.3 - #16787

Closed
testlabauto wants to merge 2 commits into
mainfrom
15060-kernel-freeze
Closed

testlabauto wants to merge 2 commits into
mainfrom
15060-kernel-freeze

Conversation

@testlabauto

@testlabauto testlabauto commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #15060

Summary

The wedge in #15060 is an ipykernel bug. ipykernel 7.0 to 7.3 read the shell ROUTER socket with a ZMQStream on the shell channel thread, but send replies with a raw send_multipart on the same socket. The raw send drains the socket's edge-triggered read edge without the stream noticing. A request that arrived at the same time is then never read, and the kernel goes silent at 0% CPU. ipykernel 7.4.0 fixes this by sending replies through the stream (ipython/ipykernel#1529), but 7.4.0 requires Python 3.11.

Positron's bundled ipykernel 6.31.0 is not affected. After #16541 moved the main console spec back to the bundled kernel, that spec went from 19 failures in 685 runs to 0 in the runs that include the fix. The alternate-ipykernel spec still loads the CI image's Python 3.10 with ipykernel 7.3.0 and kept wedging (6 of 114 runs), so it is the end-to-end regression check for this change.

This PR backports the upstream fix inside Positron's kernel, for users whose session loads ipykernel 7.0 to 7.3 (for example with python.useBundledIpykernel off):

  • positron/shell_channel.py adds a ShellChannelThread subclass whose subshell manager sends replies through the shell ZMQStream.
  • PositronIPKernelApp.init_control swaps that thread in before it starts, and init_kernel hands it the stream. The swap is gated on the installed ipykernel version, so ipykernel 6.x and 7.4+ are unchanged.
  • tests/test_shell_channel.py is adapted from the upstream regression test. It creates the strand condition deterministically and checks that Positron's thread still delivers the queued request after the reply send. It skips on ipykernel versions outside 7.0 to 7.3.

Checked in the real kernel app on ipykernel 7.3.0 that the Positron thread is the one wired in. Ruff, pyright, the existing kernel and UI test suites, and precommit pass.

Release Notes

New Features

  • N/A

Bug Fixes

Validation Steps

@:console @:web @:win

The Console Pane: Alternate Python spec is the regression check. It runs the CI image's Python 3.10 with ipykernel 7.3.0.

To check by hand:

  1. Set python.useBundledIpykernel to false.
  2. Select a Python 3.9 or 3.10 environment with ipykernel==7.3.0 installed.
  3. Start a Python console and run some code. The console should respond.
  4. In the console, run type(get_ipython().kernel.shell_channel_thread).__name__. The result is PositronShellChannelThread.

The Python kernel unit tests on 3.9 and 3.10 also run the new test, since those versions resolve to ipykernel 7.3.0.

🤖 Generated with Claude Code

ipykernel 7.0 to 7.3 send shell replies raw on the shell socket, which can
drain its read edge and strand a concurrently queued request, wedging the
kernel. Route replies through the shell ZMQStream instead, as ipykernel 7.4.0
does (ipython/ipykernel#1529).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

E2E Tests 🚀
This PR will run tests tagged with: @:critical @:console @:web @:win @:interpreter

Why these tags?
Tag Source
@:critical Always runs (required)
@:console PR description
@:web PR description
@:win PR description
@:interpreter Changed files

More on automatic tags from changed files.

readme  valid tags

… control test

The type check job installs the bundled ipykernel 6.31.0, which has no
shell channel modules, so mark those imports for pyright. The stock-path
control test did not strand on Windows, so keep only the positive
assertion, as upstream's regression test does.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@austin3dickey austin3dickey 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.

As discussed in Slack, I think this is too much maintenance for a small edge case. Someone would have to be using an EOL Python and opting out of the bundled ipykernel to encounter this.

@testlabauto

Copy link
Copy Markdown
Contributor Author

Closing due to concerns. Will fix issue with a python version bump in all the images and workflows instead,

@testlabauto
testlabauto deleted the 15060-kernel-freeze branch October 21, 2026 17:01
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python kernel stops responding to all requests when a session starts shortly after a prior session exits (wedges mid-startup, before the LSP handshake)

2 participants