Skip to content

#debugpy becomes unresponsive after rapid breakpoint suspend/resume cycles in multithreaded Python programs #2048

Closed

Description

@mengx2019

debugpy becomes unresponsive after rapid breakpoint suspend/resume cycles in multithreaded Python programs

Description

I found an issue where the debug session becomes unresponsive after repeatedly hitting a breakpoint and rapidly pressing F5 (Continue/Resume) in a multithreaded Python application.

The issue can be reproduced with a minimal example.

It does not appear to be specific to Python 3.14 free-threading, because the same behavior can also be reproduced on CPython 3.11.9.

The problem appears to be related to repeated breakpoint suspend/resume cycles and thread state handling inside debugpy/pydevd.

Environment

OS:
Windows 11

Debugger:
VS Code Python Debugger extension
debugpy: latest version

Python versions tested:

  • CPython 3.11.9
  • CPython 3.14.6
  • CPython 3.14.6 free-threaded build (python3.14t)

Minimal Reproduction

import threading
import time

def worker():
    while True:
        x = 1
        time.sleep(1)   # Put breakpoint here

for i in range(2):
    threading.Thread(target=worker).start()

while True:
    time.sleep(1)

Steps to Reproduce

  1. Open the script in VS Code.
  2. Set a breakpoint on time.sleep(1) inside worker().
  3. Start debugging with F5.
  4. When the breakpoint is hit, press F5 (Continue).
  5. Repeat rapid F5 Continue operations.
  6. After several suspend/resume cycles, the debugger becomes unresponsive.

Expected Behavior

Breakpoint suspend/resume cycles should continue normally.

Actual Behavior

After several rapid F5 Continue operations:

  • VS Code stops updating the current debug location.
  • Breakpoints no longer behave normally.
  • The debugger UI becomes stuck.
  • Restarting the debug session is required.

Technical Observation

Breakpoint handling reaches:

_pydevd_sys_monitoring._stop_on_breakpoint

and:

_do_wait_suspend()

The suspend path is entered successfully.

Possible affected areas:

  • pydevd suspend/resume state management
  • debugpy adapter DAP event ordering
  • handling of rapid continue requests
  • multithreaded breakpoint synchronization

Questions

Could this be related to a race condition in debugpy regarding:

  1. Rapid suspend/resume cycles?
  2. Multiple threads hitting the same breakpoint?
  3. Thread state cleanup after continue?
  4. DAP event ordering?

Activity

  1. mengx2019 commented on Jul 20, 2026

    @mengx2019
    Author
    Image When setting a breakpoint at the location shown in the screenshot, starting the debugger in VS Code also reproduces the following warning:

    0.31s - thread._ident is None in _get_related_thread! - thread: <Thread(Thread-7 (worker), initial)>

    This happens during debugger startup.

  2. rchiodo commented on Jul 20, 2026

    @rchiodo
    Contributor

    Worked for me with 3.15 but then reproduced with 3.11.

    Pydevd log looks like it's not sending the breakpoint for some reason. This is the end of the log after the last F5 that worked:

    0.00s - Process ContinueRequest: {
        "arguments": {
            "threadId": "*"
        },
        "command": "continue",
        "seq": 122,
        "type": "request"
    }
    
    0.00s - Resuming threads: * (except thread: None)
    0.09s - Resume not sent (it was already sent). Last resume 18 >= Last suspend 18
    0.00s - Leaving PyDB.do_wait_suspend: <Thread(Thread-6 (worker), started 31016)> (pid_23104_id_2374051995728) 2374051995728
    0.08s - Marking thread suspended. Name: Thread-7 (worker), stop_reason: 111, main_suspend: True
    0.00s - Suspending all threads except: <Thread(Thread-7 (worker), started 14700)>
    0.00s - Marking thread suspended. Name: MainThread, stop_reason: 105, main_suspend: False
    0.00s - Set tracing of frame: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py - <module>
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py - _run_code
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py - _run_module_code
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py - run_path
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py - run_file
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py - main
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy\__main__.py - <module>
    0.00s - Set tracing of frame: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\runpy.py - _run_module_as_main
    0.00s - Marking thread suspended. Name: Thread-6 (worker), stop_reason: 105, main_suspend: False
    0.00s - Set tracing of frame: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py - worker
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py - run
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py - _bootstrap_inner
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py - _bootstrap
    0.00s - SKIP set tracing of frame: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydev_bundle\pydev_monkey.py - __call__
    0.00s - PyDB.do_wait_suspend
    name: worker (line: 8)
     file: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py
     event: line
     arg: None
     step: CMD_STEP_INTO (original step: <Unknown: -1>)
     thread: <Thread(Thread-7 (worker), started 14700)>, thread id: pid_23104_id_2374051997520, id(thread): 2374051997520
    0.00s -   Stack: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py, worker, 8
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py, run, 982
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py, _bootstrap_inner, 1045
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py, _bootstrap, 1002
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydev_bundle\pydev_monkey.py, __call__, 1150
    0.00s - Skipping per-thread thread suspend notification.
    0.00s - Thread suspend mode: single notification
    0.00s - Sending suspend notification.
    0.00s - sending cmd (http_json) --> CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION {"type": "event", "event": "stopped", "body": {"reason": "breakpoint", "threadId": 3, "preserveFocusHint": false, "allThreadsStopped": true}, "seq": 326, "pydevd_cmd_id": 157}
    
    0.83s - PyDB.do_wait_suspend
    name: <module> (line: 13)
     file: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py
     event: line
     arg: None
     step: CMD_THREAD_SUSPEND (original step: <Unknown: -1>)
     thread: <_MainThread(MainThread, started 44324)>, thread id: pid_23104_id_2374008917776, id(thread): 2374008917776
    0.00s -   Stack: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py, <module>, 13
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py, _run_code, 118
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py, _run_module_code, 127
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py, run_path, 310
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py, run_file, 361
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py, main, 542
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy\__main__.py, <module>, 71
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\runpy.py, _run_code, 88
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\runpy.py, _run_module_as_main, 198
    0.00s - Skipping per-thread thread suspend notification.
    0.00s - Thread suspend mode: single notification
    0.00s - Suspend not sent because stop reason is thread suspend and pause was not requested.
    0.09s - PyDB.do_wait_suspend
    name: worker (line: 6)
     file: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py
     event: line
     arg: None
     step: CMD_THREAD_SUSPEND (original step: <Unknown: -1>)
     thread: <Thread(Thread-6 (worker), started 31016)>, thread id: pid_23104_id_2374051995728, id(thread): 2374051995728
    0.00s -   Stack: C:\Users\rchiodo\source\testing\test_debugpy_multithreaded\test_quickbreak.py, worker, 6
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py, run, 982
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py, _bootstrap_inner, 1045
    0.00s -   Stack: c:\Users\rchiodo\AppData\Local\Programs\Python\Python311\Lib\threading.py, _bootstrap, 1002
    0.00s -   Stack: c:\Users\rchiodo\.vscode-insiders\extensions\ms-python.debugpy-2026.7.11831010-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydev_bundle\pydev_monkey.py, __call__, 1150
    0.00s - Skipping per-thread thread suspend notification.
    0.00s - Thread suspend mode: single notification
    0.00s - Suspend not sent because stop reason is thread suspend and pause was not requested.
    
  3. mengx2019 commented on Jul 21, 2026

    @mengx2019
    Author

    During my testing, when rapidly pressing Continue, an additional ContinueRequest is received unexpectedly. After that, the debugger enters an unresponsive state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions