Repository navigation
Closed
Labels
Milestone
Description
Bug summary
I am trying to create a plot in a for-loop. I can move each plot around, but even if I close it (click the ❌, use plt.close()), all prior plots are still displayed behind the newest plot. If I try to close plots (click the ❌) out of order, it results in a segfault.
Code for reproduction
import numpy as np
import matplotlib.pyplot as plt
for _ in range(100):
fig, ax = plt.subplots()
x = np.random.rand(10)
y = np.random.rand(10)
ax.plot(x, y)
plt.show()
plt.close()Actual outcome
> python3 -X faulthandler test.py
Fatal Python error: Segmentation fault
Current thread 0x00000001f5cc1e80 (most recent call first):
File "/Users/Adam/torchgeo/.venv/lib/python3.14/site-packages/matplotlib/backends/backend_macosx.py", line 180 in start_main_loop
File "/Users/Adam/torchgeo/.venv/lib/python3.14/site-packages/matplotlib/backend_bases.py", line 3702 in show
File "/Users/Adam/torchgeo/.venv/lib/python3.14/site-packages/matplotlib/pyplot.py", line 646 in show
File "/Users/Adam/Downloads/test.py", line 9 in <module>
Current thread's C stack trace (most recent call first):
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at _Py_DumpStack+0x44 [0x101cf10a4]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at faulthandler_dump_c_stack+0x54 [0x101d68f48]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at faulthandler_fatal_error+0x16c [0x101d68df8]
Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x189b4b744]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at _Py_Dealloc+0x38 [0x1013b0238]
Binary file "/Users/Adam/torchgeo/.venv/lib/python3.14/site-packages/matplotlib/backends/_macosx.cpython-314-darwin.so", at -[Window close]+0x7c [0x106c59f70]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSWindow __close]+0x178 [0x18e2e2ad8]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSApplication(NSResponder) sendAction:to:from:]+0x230 [0x18e1c66c0]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSControl sendAction:to:]+0x48 [0x18e1c6460]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at __26-[NSCell _sendActionFrom:]_block_invoke+0x64 [0x18e1c63a4]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSCell _sendActionFrom:]+0xcc [0x18e1c62cc]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSButtonCell _sendActionFrom:]+0x60 [0x18e1c61c8]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at NSControlTrackMouse+0x5d4 [0x18e1c37b0]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSCell trackMouse:inRect:ofView:untilMouseUp:]+0x90 [0x18e1c31b0]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:]+0xe4 [0x18e1c307c]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSControl(_NSTracking) _mouseDown:]+0x260 [0x18e712a74]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSControl(_NSTracking) mouseDown:]+0x68 [0x18e7127e8]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:]+0xe70 [0x18e1c1c04]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:]+0x1ec [0x18e1501f4]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSWindow(NSEventRouting) sendEvent:]+0x17c [0x18e14fe64]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSApplication(NSEventRouting) sendEvent:]+0x4fc [0x18ebc040c]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSApplication _handleEvent:]+0x3c [0x18e80d664]
Binary file "/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit", at -[NSApplication run]+0x198 [0x18e01f164]
Binary file "/Users/Adam/torchgeo/.venv/lib/python3.14/site-packages/matplotlib/backends/_macosx.cpython-314-darwin.so", at show+0x74 [0x106c5e970]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at _TAIL_CALL_CALL_NON_PY_GENERAL.llvm.10127954890374434623+0x104 [0x101705924]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at _PyFunction_Vectorcall+0x338 [0x10167429c]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at method_vectorcall.llvm.1628862021063799139+0x94 [0x1016b7330]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at _TAIL_CALL_CALL_FUNCTION_EX.llvm.10127954890374434623+0x10c [0x101469578]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at _PyEval_Vector+0x30c [0x1014f5d00]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at PyEval_EvalCode+0xa0 [0x10150588c]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at run_mod.llvm.9148091775861049191+0x124 [0x101517a7c]
Binary file "/Users/Adam/.local/share/uv/python/cpython-3.14.4-macos-aarch64-none/lib/libpython3.14.dylib", at pyrun_file+0xa4 [0x101645880]
<truncated rest of calls>
Extension modules: numpy._core._multiarray_umath, numpy.linalg._umath_linalg, PIL._imaging, kiwisolver._cext, matplotlib.backends._macosx, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._generator, numpy.random._mt19937, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand (total: 14)
fish: Job 1, 'python3 -X faulthandler test.py' terminated by signal SIGSEGV (Address boundary error)
Expected outcome
I would expect no phantom plots and no segfaults.
Additional information
Tried Python 3.13 and 3.14 in fresh uv environments, no luck so far. Happy to try other debugging suggestions.
Operating system
macOS Tahoe 26.5.1
Matplotlib Version
3.11.0
Matplotlib Backend
macosx
Python version
3.14.4
Jupyter version
N/A
Installation
uv
Activity
QuLogic commentedon Jul 8, 2026
This looks like #31106, but it should have been fixed in 3.11.0. @iccir
iccir commentedon Jul 9, 2026
@adamjstewart If you open Console and click on "Crash Reports", can you attach the full crash report file?
iccir commentedon Jul 9, 2026
The crash is caused by the
Py_DECREF(manager)in-[Window close]. In the event that a window doesn't actually close and-[Window close]is called multiple times, we will over-release the manager and crash. This part is fixed by PR #31855.The remaining question is "why is the window not closing." The only way that the over-release could happen is if
-[Window close], and thus-[NSWindow close], was called at least once. That should have closed the window. The fact that it didn't is either a rare system bug of some kind, or (possibly) there's some kind of binary getting loaded into the Python process that changes the behavior of-[NSWindow close].I haven't been able to reproduce on Tahoe 26.5. I'm not able to update to 26.5.1 since it's no longer available, but I'm installing 26.5.2 now.
Edit: I cannot reproduce on 26.5.2.
adamjstewart commentedon Jul 9, 2026
I believe my problem is a bit different than #31106, recorded a video to demonstrate:
Screen.Recording.2026-07-09.at.12.20.55.PM.mov
Here is the crash report:
proactive_event_tracker-com_apple_Trial-com_apple_triald_system_2026-07-08-203342_Vesuvius.txt
iccir commentedon Jul 9, 2026
@adamjstewart - I need the IPS file for the crashed Python process. It should look like the attached screenshot (P.S. Nice computer name!)
iccir commentedon Jul 9, 2026
@adamjstewart - Or you can copy-paste the whole contents of the crash dialog that pops up. Specifically, I need to see the
Binary Images:section. That said, it looks like you have System Integrity Protection enabled, so it's doubtful there is something injecting into the Python process, but I want to be 100% sure.adamjstewart commentedon Jul 9, 2026
Full report:
python3.14-2026-07-09-122132.txt
Binary Images section:
iccir commentedon Jul 9, 2026
@adamjstewart - Thank you! I don't see anything in that Binary Image list that could be affecting window closing.
Can you do the following:
adamjstewart commentedon Jul 9, 2026
Log:
Screen recording:
Screen.Recording.2026-07-09.at.2.38.32.PM.mov
iccir commentedon Jul 9, 2026
Thanks!
Here's what is happening: for some unknown reason, something in the process is maintaining a strong reference to each
NSWindowinstance. Per the logs, the NSWindow'sdelegateis getting set tonil; hence, eitherFigureManager_destroyorFigureManager_deallocis being called. The code in question:That
-releaseshould be the last strong reference to the window. One would expect-[NSWindow dealloc]to get called shortly after. However, that doesn't happen. Until-deallocis called, the window will never be removed from theNSApplications.windowsarray.The next time
show()is called, we iterate over all known windows and show them:So that causes the window to re-appear. However, without #31855, that window contains an uncleared backpointer to the FigureManager, so it's going to explode if the manager goes away.
show()should probably iterate overWindowclasses (those that are owned by a FigureManager) instead of all living windows.While #31855 fixes the crash, it likely doesn't fix the fact that something outside of our control is maintaining a strong reference to the window. I don't know if that's fixable or not. It's likely that strong reference would eventually go away in another run loop cycle or two, it's just that we immediately spin down the event loop and then spin it back up on the next call to
show().@adamjstewart - Can you do the following:
Use the command
heap -q --addresses=Window python3 | grep Window. This will tell you how many active Windows are still allocated in the process.If you run your original Python script, you should see window objects accumulate with each iteration.
Try to run the following (slightly scary-looking) script:
Let me know if you see the Window objects continue to accumulate or go away. Maybe change that
0.001to a higher value too if they are still accumulating.adamjstewart commentedon Jul 9, 2026
Can confirm this behavior.
First plot displays, I can close it without it coming back, but the second plot never displays. Possibly stuck in a loop somewhere? I can also try a
time.sleep()ordel figif that makes sense.iccir commentedon Jul 9, 2026
Yeah, I'm seeing that now too. That's what I get for trying to be clever and working around another bug ;)
Can you try this:
And then quickly hit the close button as the windows appear? We are hoping to see previously-closed windows not re-appear and for the
heapcommand to not show the previously-closed ones.adamjstewart commentedon Jul 9, 2026
This works, although it spawns a new figure every 2 sec instead of waiting for me to close the old one.
iccir commentedon Jul 9, 2026
So, to confirm, as long as you are quick enough you can keep the window count down to 1?
This is all great information, thank you for all the help thus far!
adamjstewart commentedon Jul 9, 2026
Correct
iccir commentedon Jul 10, 2026
@adamjstewart - I believe that the following workaround should work until I can get a proper fix landed. You may need to add aplt.close()afterplt.show()or increase thestart_event_looptimeout a bit.See note below: this isn't going to work as the AppKit seems to retain the last-animated window.
Adding additional fix for matplotlib#32019
iccir commentedon Jul 10, 2026
Update: I can reproduce this 100% on Tahoe if I turn off Reduce Motion. The window is being retained by AppKit due to the order-out animation and AppKit seems to keep a strong reference to it until the next window is ordered in.
iccir commentedon Jul 10, 2026
After some testing today, I can confirm that this is fixed by #31855. AppKit is still maintaining a reference to one of our
Windowobjects, but that eventually clears when the next window is shown.QuLogic commentedon Jul 16, 2026
That's good; is there a more focused fix that we can backport or is that PR the best option?
iccir commentedon Jul 17, 2026
I think that the PR is the best option. I could try to make a more-focused fix with just 80a4327 and parts of the FigureManager_dealloc/FigureManager_destroy changes; however, I'm uneasy about the amount of testing those fixes in isolation would received compared to the amount that the whole ARC PR has received.