windmill-labs/windmill · error

Not connected to DAP server

Error message

Not connected to DAP server

What it means

DapClient.sendRequest() is the single gateway for all Debug Adapter Protocol commands (launch, setBreakpoints, continue, stepOver, stepIn, configurationDone...). It throws 'Not connected to DAP server' when the underlying WebSocket is absent or not in OPEN state, so a request would otherwise be silently lost.

Source

Thrown at frontend/src/lib/components/debug/dapClient.ts:170

	}

	/**
	 * Disconnect from the DAP server.
	 */
	disconnect(): void {
		if (this.ws) {
			this.ws.close()
			this.ws = null
		}
		debugState.set({ ...initialState })
	}

	/**
	 * Send a request to the DAP server and wait for a response.
	 */
	private async sendRequest(command: string, args?: Record<string, unknown>): Promise<DAPMessage> {
		if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
			throw new Error('Not connected to DAP server')
		}

		const seq = this.seq++
		const message: DAPMessage = {
			seq,
			type: 'request',
			command,
			arguments: args
		}

		const timeoutMs = REQUEST_TIMEOUT_MS_BY_COMMAND[command] ?? DEFAULT_REQUEST_TIMEOUT_MS

		return new Promise((resolve, reject) => {
			const timeout = setTimeout(() => {
				this.pendingRequests.delete(seq)
				reject(new Error(`Request timeout: ${command} (after ${timeoutMs}ms)`))
			}, timeoutMs)

View on GitHub (pinned to e474e8803c)

Solutions

  1. Check the WebSocket connection state / onclose handler to find why the socket dropped (server exit, network, timeout).
  2. Await connect() and only then send DAP commands; gate UI actions on a connected flag.
  3. Restart the debug session (reconnect and re-launch) once the socket is OPEN again.
  4. Inspect DAP server logs for a crash or unhandled adapter error preceding the disconnect.
  5. Disable/queue stepping UI while readyState !== WebSocket.OPEN.

Example fix

// before
await dapClient.launch(config) // throws if socket dropped
// after
if (!dapClient.isConnected()) { await dapClient.connect() }
await dapClient.launch(config)
Defensive patterns

Strategy: type-guard

Validate before calling

// expose a public helper on DapClient, or check the socket state externally
// if (!dapClient.isReady()) { await dapClient.connect() }

Type guard

function dapReady(client: DapClient): boolean {
  return client['ws']?.readyState === WebSocket.OPEN
}

Try / catch

try {
  await dapClient.continue_(threadId)
} catch (e) {
  if (e.message === 'Not connected to DAP server') {
    showToast('Debugger disconnected — restart the session')
    await reconnectAndRelaunch()
  } else throw e
}

Prevention

When it happens

Trigger: Calling launch(), continue_(), stepOver(), stepIn(), configurationDone(), response(), etc. before connect() resolved, after the WebSocket closed (debuggee exited or server dropped), or while a reconnect is still in progress.

Common situations: Debugger UI buttons clicked after the debug session ended; the DAP server crashed or the websocket timed out mid-session; calling connect() without awaiting it before issuing commands; hot reload destroying the socket.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/832f654df2a79a53. Report an issue: GitHub.