can1357/oh-my-pi · error · Error
DAP adapter ${this.adapter.name} is not running
Error message
DAP adapter ${this.adapter.name} is not running What it means
DapClient.sendRequest refuses to send a DAP request over a transport that has already been disposed. Once #disposed is set (after disconnect/termination of the client), any further request — initialize, scopes, continue, etc. — cannot reach the adapter and the client throws immediately instead of hanging until the request timeout. It guards callers against writing into a dead pipe.
Source
Thrown at packages/coding-agent/src/dap/client.ts:444
}
timeout = setTimeout(() => {
cleanup();
reject(new Error(`DAP event ${event} timed out after ${timeoutMs}ms`));
}, timeoutMs);
return promise;
}
async sendRequest<TBody = unknown>(
command: string,
args?: unknown,
signal?: AbortSignal,
timeoutMs: number = DEFAULT_REQUEST_TIMEOUT_MS,
): Promise<TBody> {
if (signal?.aborted) {
throw signal.reason instanceof Error ? signal.reason : new ToolAbortError();
}
if (this.#disposed) {
throw new Error(`DAP adapter ${this.adapter.name} is not running`);
}
const requestSeq = ++this.#requestSeq;
const request: DapRequestMessage = {
seq: requestSeq,
type: "request",
command,
arguments: args,
};
const { promise, resolve, reject } = Promise.withResolvers<TBody>();
// Suppress "unhandled rejection" if the request timer or abort fires
// before the caller's `await` subscribes — e.g. while #writeMessage is
// still racing a wedged stdin flush. The caller's own `await` still
// receives the rejection normally; this handler is a passive guard.
promise.catch(() => {});
let timeout: NodeJS.Timeout | undefined;
const cleanup = () => {
if (timeout) clearTimeout(timeout);View on GitHub (pinned to 9690622007)
Solutions
- Re-obtain a live session: re-launch or re-attach the debug session before issuing further requests
- Check client.isAlive() (or catch this error) before reusing a stored DapSession/DapClient reference
- Make sure no concurrent code path calls disconnect/terminate while requests are still in flight; serialize session teardown with pending requests
- If you keep a reference across awaits, re-fetch the active session from DapSessionManager instead of caching the client
Example fix
// before
const scopes = await cachedClient.sendRequest('scopes', { frameId });
// after
if (!cachedClient.isAlive()) {
session = await manager.launch(config); // recreate the session
}
const scopes = await session.client.sendRequest('scopes', { frameId }); Defensive patterns
Strategy: try-catch
Validate before calling
if (!client.isAlive()) {
client = await DapClient.connect({ adapter, cwd });
} Type guard
function isUsableClient(c: DapClient | null | undefined): c is DapClient {
return !!c && c.isAlive();
} Try / catch
try {
return await client.sendRequest(command, args, { signal });
} catch (err) {
if (String((err as Error).message).includes('is not running')) {
client = await DapClient.connect({ adapter, cwd }); // recreate
return await client.sendRequest(command, args, { signal });
}
throw err;
} Prevention
- Never cache DapClient references across session lifecycle; fetch the active session from DapSessionManager
- Check isAlive() before issuing requests after any await that could allow disposal
- Serialize session teardown (disconnect/terminate) with in-flight requests via a mutex or queue
- Subscribe to adapter exit/close events to invalidate cached clients immediately
When it happens
Trigger: Calling any request method on a DapClient after disconnect() or after the session was terminated/disposed; reusing a stale DapSession whose client was disposed when the adapter exited; a race where an abort check passes but disposal happens between it and the disposed check.
Common situations: A debug adapter crashed or was terminated and the tool then issues follow-up commands (scopes, variables, stack_trace); a queued async task continues after the session manager disposed the session on adapter exit; a UI keeps issuing evaluate/continue calls after the user stopped debugging.
Related errors
- DAP adapter ${this.adapter.name} exited before write complet
- Adapter process exited before socket was ready
- Socket not ready after ${timeoutMs}ms
- No active stack frame. Run stack_trace first or supply frame
- Debug session ${root.id} is still active. Terminate it befor
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f45250d53d8bb242.
Report an issue: GitHub.