## TL;DR
When interrupt does nothing, the kernel is stuck where signals cannot reach it: inside a native library call, a C-level loop, or a deadlocked thread. One more interrupt will not help. Restart the kernel, then defend the notebook: wrap long calls with timeouts, avoid uninterruptible native loops, and checkpoint results so a restart costs minutes, not hours.

```text
jupyter notebook kernel busy forever, interrupt not working, kernel hung
```

## Use this when
- The kernel shows busy for a long time and interrupt (twice) changes nothing.
- The stuck cell calls into native code (C extensions, GPU, network).
- This recurs with the same cell or library.

## Not for this skill when
- The cell is just slow but progressing. Let it finish or optimize it.
- Interrupt works but is slow. That is normal signal delivery delay.

## Steps
1. Try interrupt once more and wait 60 seconds; some native calls return between iterations. Verify: whether the kernel recovers on its own.
2. If still busy, restart the kernel from the UI. Verify: the kernel status returns to idle.
3. Identify the wedging call by re-running the cell with smaller input or added logging. Verify: you can name the call that hangs.
4. Add a timeout around it (signal-based for CPU work, library timeout params for network/GPU). Verify: the timeout fires instead of wedging.
5. Checkpoint the notebook's state to disk before the risky cell. Verify: a future restart resumes from the checkpoint.

## Variant phrasings
### kernel busy interrupt not working
Short form. Restart, then add timeouts.

### jupyter kernel hung uninterruptible
The native-code phrasing. Signals cannot reach it.

### interrupt kernel does nothing jupyter
Symptom phrasing. One more interrupt will not help.

Compatibility: ipykernel 6.x on all platforms. Signal handling limits are OS-level, not version-specific.

## Why it happens
Python's interrupt handling only runs between bytecode instructions. A thread parked inside a C extension, a BLAS call, or a blocking socket read never returns to the interpreter loop, so the SIGINT sits in a queue nobody drains. The kernel is not ignoring you; it is physically unable to hear you until the native call returns, which for a true hang is never.

## Edge cases / pitfalls
- Repeated interrupts queue up and can fire later in a surprising cell. After a restart the queue is gone; do not mash interrupt pre-restart and then wonder.
- Restarting loses all variables. That is the price; the checkpoint habit is what makes it cheap.
- Some libraries catch KeyboardInterrupt internally and keep going. Read their docs for a real cancellation API.
- A kernel that is busy forever on every cell may have a wedged ZMQ channel rather than wedged code. Restart distinguishes the two.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_u3XKFOBJC_pn6zC4Nw3Hcg
