helix-editor/helix · error · helix_dap::Error

DAP request failed

Error message

DAP request failed

What it means

Fallback message used when a Debug Adapter Protocol response arrives with success = false and the adapter supplied no human-readable 'message' field. It is wrapped as Error::Other(anyhow!(message)) after the 20s timeout and stream-closed checks already passed, so the request reached the adapter and was explicitly rejected.

Source

Thrown at helix-dap/src/client.rs:294

                arguments,
            };

            server_tx
                .send(Payload::Request(req))
                .map_err(|e| Error::Other(e.into()))?;

            // TODO: specifiable timeout, delay other calls until initialize success
            let response = timeout(Duration::from_secs(20), callback_rx.recv())
                .await
                .map_err(|_| Error::Timeout(id))? // return Timeout
                .ok_or(Error::StreamClosed)??;

            if !response.success {
                let message = response
                    .message
                    .clone()
                    .unwrap_or_else(|| "DAP request failed".to_string());
                return Err(Error::Other(anyhow!(message)));
            }

            Ok(response.body.unwrap_or_default())
        }
    }

    pub async fn request<R: helix_dap_types::Request>(
        &self,
        params: R::Arguments,
    ) -> Result<R::Result>
    where
        R::Arguments: serde::Serialize,
    {
        // a future that resolves into the response
        let json = self.call::<R>(params).await?;
        let response = serde_json::from_value(json)?;
        Ok(response)
    }

View on GitHub (pinned to 079a789e8c)

Solutions

  1. Check the adapter's own log/stderr for the real rejection reason - this message means the adapter sent no explanation
  2. Rule out the startup race: retry the operation after the session is fully initialized/launched (e.g. set breakpoints after 'stopped' or launch completes)
  3. Verify the arguments (file paths must exist and be absolute; line numbers are converted internally) and the adapter's capabilities before issuing optional requests
  4. Update or switch the adapter (e.g. codelldb <-> lldb-dap) if the request is unsupported in your version
Defensive patterns

Strategy: try-catch

Validate before calling

// Before optional requests, gate on the adapter's capabilities:
if let Some(caps) = debugger.caps() {
    if !caps.supports_configuration_done_request.unwrap_or(false) {
        return Ok(()); // adapter will reject it
    }
}

Try / catch

// All dap::Client request wrappers return Result; handle Error::Other and
// keep the session alive - show the message but don't tear down:
match debugger.set_breakpoints(path, bps).await {
    Ok(_) => {}
    Err(dap::Error::Other(e)) => status_msg(format!("debugger rejected request: {e}")),
    Err(dap::Error::Timeout(_)) => retry_once().await,
    Err(dap::Error::StreamClosed) => restart_session(),
}

Prevention

When it happens

Trigger: Any dap::Client::request call whose response has success:false and message:None - commonly setBreakpoints before the adapter finished initializing, evaluate/continue while no thread is stopped, or a request the adapter lacks the capability for (checked against caps elsewhere).

Common situations: Race at session start: Helix sends a request before the initialize/launch handshake completes; adapter version change removed support for a request (e.g. unsupported breakpoint features); adapter-specific quirks (lldb-dap vs codelldb vs debugpy) rejecting arguments like invalid paths or 0-based/1-based line mismatches.

Related errors


AI-assisted analysis of helix-editor/helix@079a789e8c (2026-08-16). Data as JSON: /api/errors/d5036df9f05efa76. Report an issue: GitHub.