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

  1. Wait for a `stopped` event (a breakpoint hit or pause) before issuing thread-dependent requests; the manager already gates some ops on status === 'stopped'
  2. Verify the debuggee actually started: check the program path/args in the launch config and inspect adapter console output for early-exit errors
  3. Re-launch or re-attach the session; the debuggee may have terminated
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/457a87a3f69b865f. Report an issue: GitHub.