can1357/oh-my-pi · error · Error
Debugger reported no threads.
Error message
Debugger reported no threads.
What it means
DapSessionManager resolves a thread id after requesting the DAP `threads` response; when the debugger returns an empty thread list (or none at all), it throws because every follow-up request (stack traces, breakpoints, stepping) needs a thread id. This indicates the debug adapter is alive but reported no debuggable threads.
Source
Thrown at packages/coding-agent/src/dap/session.ts:1666
snapshot: buildSummary(resultSession),
state: "running",
timedOut: resultSession.status === "running",
};
}
}
async #resolveThreadId(session: DapSession, signal?: AbortSignal, timeoutMs: number = 30_000): Promise<number> {
if (session.stop.threadId !== undefined) {
return session.stop.threadId;
}
if (session.threads.length > 0) {
return session.threads[0].id;
}
const response = await session.client.sendRequest<DapThreadsResponse>("threads", undefined, signal, timeoutMs);
session.threads = response?.threads ?? [];
const threadId = session.threads[0]?.id;
if (threadId === undefined) {
throw new Error("Debugger reported no threads.");
}
return threadId;
}
async #sendRequestWithConfig<TBody>(
session: DapSession,
command: string,
args: unknown,
signal?: AbortSignal,
timeoutMs: number = 30_000,
): Promise<TBody> {
await this.#ensureConfigurationDone(session, signal, timeoutMs);
const body = await session.client.sendRequest<TBody>(command, args, signal, timeoutMs);
this.#touchSessionAndAncestors(session);
return body;
}
async #ensureConfigurationDone(View on GitHub (pinned to 9690622007)
Solutions
- Wait for a `stopped` event (a breakpoint hit or pause) before issuing thread-dependent requests; the manager already gates some ops on status === 'stopped'
- Verify the debuggee actually started: check the program path/args in the launch config and inspect adapter console output for early-exit errors
- Re-launch or re-attach the session; the debuggee may have terminated
- Catch the error and retry after a short delay if you are racing adapter startup
Example fix
// before const threadId = await manager.getThreadId(); // throws if called right after launch // after await manager.waitForStoppedEvent(); // or pause() the debuggee first const threadId = await manager.getThreadId();
Defensive patterns
Strategy: retry
Validate before calling
const threads = await session.client.sendRequest('threads');
if (!threads?.threads?.length) {
throw new SkipOperation('debugger has no threads yet');
} Type guard
function hasThreads(r) { return Array.isArray(r?.threads) && r.threads.length > 0; } Try / catch
try {
const threadId = await manager.getThreadId();
} catch (err) {
if (err.message === 'Debugger reported no threads.') {
await Bun.sleep(250); // adapter startup race
// retry once, else surface 'debuggee not running'
}
} Prevention
- Only issue thread-dependent DAP requests after a stopped event
- Verify the debuggee program launches and stays alive
- Treat zero threads as 'debuggee exited' in your UI
When it happens
Trigger: Calling any public DapSessionManager method that resolves the first thread (`#resolveThreadId`) while `response.threads` is empty or undefined — e.g. evaluating, setting breakpoints, or resuming right after launch/attach before the debuggee started, or after the debuggee exited but the adapter session is still alive.
Common situations: Attaching to a process that already exited; launching a program that crashed immediately; adapters (e.g. node/js-debug, python debugpy) that return zero threads during startup races; querying too early before a 'stopped' event produced any threads.
Related errors
- No active debug session. Launch or attach first.
- memory_reference is required for read_memory
- count is required for read_memory
- memory_reference is required for write_memory
- data is required for write_memory
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/457a87a3f69b865f.
Report an issue: GitHub.