Why Your Jupyter Notebook Lies to You: Execution State, Kernel Restarts, and How to Trust Your Outputs
Jupyter notebooks display outputs that may not match the kernel's state. Learn why kernel restarts invalidate execution state, how to verify outputs, and when to re-execute for reproducibility.
26 Aug 2026, 00:59 UTC

The notebook that worked yesterday
Here is a scenario most Jupyter users have hit: a notebook ran perfectly last week, you reopen it today, and the numbers don't match what's on screen. The kernel was restarted at some point, outputs were lost, and what you're looking at is a mix of stale results and fresh cells. The takeaway is simple: a notebook's displayed outputs are not a report of what happened — they are whatever the front-end last rendered, which may or may not correspond to any coherent execution state.
This piece explains why that happens, and how to make notebook outputs trustworthy.
Cells, kernels, and the illusion of continuity
A Jupyter notebook is a JSON document. The front-end (JupyterLab, classic Notebook, VS Code) is just a viewer. The kernel — a separate process — owns the state. When you run a cell, the front-end sends an execute_request message to the kernel; results come back as execute_result or display_data messages, which the front-end renders and writes into the notebook file.
The problem: outputs are only persisted when the notebook is saved. If the kernel crashes or is restarted, anything since the last checkpoint is gone. Worse, the front-end reconnects to a new kernel with the same session, and the notebook still shows the old outputs, even though the kernel state behind them no longer exists.
Why outputs survive kernel restarts (and why that's misleading)
Outputs are stored in the notebook JSON, not the kernel. Restarting the kernel does not clear them. The front-end will happily display a DataFrame that no longer exists in memory. This is by design — it lets you view a notebook without running anything — but it means the displayed state is a snapshot, not a live view.
Key points:
- Outputs are only written to disk on save (checkpoint).
- Restarting the kernel invalidates the execution state but leaves outputs untouched.
- Rich outputs (HTML, SVG, PNG) are rendered by the front-end; the kernel only sends MIME-typed data.
- Front-end and kernel versions can disagree on how outputs are ordered or serialized.
Making outputs trustworthy
The fix is to treat the notebook as a source of truth, not a transcript. Use nbconvert to re-execute and compare:
jupyter nbconvert --to notebook --execute --inplace example.ipynbRun this in the notebook's directory. It requires write permission and will overwrite the file. If the re-executed outputs differ from the displayed ones, the notebook was not reproducible.
For automation, use --execute in CI and diff the output cells. If they match, the notebook is stable. If not, the displayed outputs are stale.
When to worry
Not every notebook needs to be reproducible. But if you're using notebooks for reporting or pipeline steps, stale outputs are a real risk. The practical rule: if you can't re-execute and verify, don't trust the outputs.
Actionable closing: add nbconvert --execute to your workflow, and treat any mismatch as a signal to restart the kernel and re-run from scratch.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.