“Thread not found” when debugging Rust inline tests with nvim-dap + latest lldb-dap
### Debug adapter definition and debug configuration
Install the adapter via [`rustaceanvim `](https://github.com/mrcjkb/rustaceanvim)
dap-config:
```
dap.adapters.lldb = {
type = "executable",
command = vim.fn.exepath("lldb-dap"),
name = "lldb",
}
```
Install LLDB-DAP from latest LLVM.
Install rust-analyzer.
### Debug adapter version
Homebrew LLVM version 21.1.8
### Steps to Reproduce
1. Create a rust project via `cargo new`
2. Add an inline test like
```rust
fn main() {
println!("Hello World");
}
#[test]
fn t() {
let a = 1;
let b = 2;
let sum = a + b
println!("{}", sum);
}
```
3. Set a breakpoint at the first line of the inline test.
4. Run `:RustLsp debuggables` and select `test --no-run --package rust ...`
### Expected Result
#### Summary
When debugging Rust inline tests using nvim-dap together with the latest lldb-dap, a stopped event reports a thread ID that is not found in the thread list returned by the DAP threads request. This results in an error like `Thread not found`., but execution can still continue with step over etc.
This issue occurs specifically when debugging Rust inline tests (e.g., `#[test]`), which is a very common workflow in Rust development.
#### My Investigation
##### Rust inline tests
- Rust inline tests are compiled into a main function that spawns a new thread to run the test logic.
- rustc generates a `main()` that launches the test thread, then maps test locations back to the inline test.
- The actual testing thread has a different thread ID than the main thread.
##### nvim-dap thread handling
In nvim-dap (session.lua), thread state is updated like:
dap/session.lua#L696-L797
- `update_threads()` calls DAP threads to build the thread list.
- Then it checks for existence of self.threads[stopped.threadId].
The error happens because the initial threads response does not include the new test thread, so stopped.threadId is not in the list.
##### lldb-dap behavior
Recent commits to llvm-project added handling to avoid LLDB hanging when listing thousands of threads in some cases. For the initial `threads` request, lldb-dap returns an initial cached list that may not yet include newly started threads. Only a later threads request returns the complete set.
Thus:
- The first threads request returns incomplete threads (for example, only `main`).
- The second threads request returns both main and test threads.
##### Trace
- nvim-dap receives a StoppedEvent with a threadId for the test thread.
- nvim-dap calls update_threads() using DAP threads request.
- The initial thread list returned by lldb-dap does not include the new test thread.
- nvim-dap fails to find stopped.threadId in its internal threads map.
- The missing thread causes a Thread not found situation before a subsequent (full) threads list arrives.
This mismatch causes nvim-dap to think the stopped thread does not exist.
(Logs illustrating the behavior above.) 
### Actual Result
Example logs
```
[stopped event] threadId = 1139446
[initial threads]
threads = [{ id = 1139438, name = "Thread 3" }]
[later threads]
threads = [
{ id = 1139438, name = "main" },
{ id = 1139446, name = "tet" }
]
```
[dap.log](https://github.com/user-attachments/files/24399889/dap.log)
4 条评论