Hmbown/CodeWhale · error

ds4_probe_error(config, &error.to_string())

Error message

ds4_probe_error(config, &error.to_string())

What it means

The doctor's DS4 probe calls `GET /v1/models` on a local DS4 endpoint with a 15-second timeout (tokio::time::timeout around client.list_models()). If the inner request itself errors, the error is formatted via ds4_probe_error(config, ...) and bailed. It means the doctor could not complete the model-listing request against the DS4 server.

Solutions

  1. Read the inner error text rendered by ds4_probe_error — connection refused vs. auth vs. TLS tells you which fix applies.
  2. Confirm the DS4 server is running and reachable: `curl <endpoint>/v1/models`.
  3. Fix the DS4 endpoint URL/API key in the Codewhale config to match the running server.
  4. If auth fails, supply the correct credentials DS4 expects before re-running the doctor.

Example fix

// before: probe fails with ds4_probe_error(...) — connection refused on port 8080
// after: start DS4 on the configured port or correct the endpoint
ds4 serve --port 8080 &
# ensure config endpoint = http://127.0.0.1:8080/v1
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe the endpoint before running the doctor
let resp = reqwest::get(format!("{endpoint}/v1/models")).await;
if let Err(e) = resp {
    eprintln!("DS4 endpoint unreachable: {e}"); // connection refused / auth / TLS detail
}

Try / catch

match probe_result {
    Err(e) if e.is_connect() => eprintln!("start the DS4 server first"),
    Err(e) if e.status() == Some(401) => eprintln!("check DS4 API key"),
    Err(e) => eprintln!("DS4 probe failed: {e}"),
    Ok(_) => {},
}

Prevention

When it happens

Trigger: probe_ds4_models awaits client.list_models() and receives Ok(Err(error)) — connection refused (server not running), TLS failure, 401/403 from the endpoint, or any reqwest-level error wrapped by the 15s timeout future.

Common situations: DS4 server not started or listening on a different port than configured; the endpoint URL in config points at the wrong host; the server requires an API key that is missing or wrong; firewall blocking localhost/port.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/72d68067526e478f. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/doctor.rs:579

}

/// Probe DS4 through its cheap `/v1/models` contract instead of waking the
/// model for a completion. The selected model must be advertised.
pub(crate) async fn probe_ds4_models(config: &crate::config::Config) -> anyhow::Result<()> {
    use crate::client::DeepSeekClient;
    use crate::core::model_client::ModelClient;

    let endpoint = crate::client::redact_url_for_display(&config.deepseek_base_url());
    let client = DeepSeekClient::new(config)?;
    let configured_alias = client.model().to_string();
    let models = match tokio::time::timeout(
        std::time::Duration::from_secs(15),
        client.list_models(),
    )
    .await
    {
        Ok(Ok(models)) => models,
        Ok(Err(error)) => anyhow::bail!(ds4_probe_error(config, &error.to_string())),
        Err(_) => anyhow::bail!("DS4 /v1/models timed out after 15 seconds at {}", endpoint),
    };
    if !models
        .iter()
        .any(|available| available.id == configured_alias)
    {
        let advertised = models
            .iter()
            .take(8)
            .map(|available| available.id.as_str())
            .collect::<Vec<_>>()
            .join(", ");
        anyhow::bail!(
            "DS4 /v1/models at {} did not list configured alias '{configured_alias}' (advertised: {})",
            endpoint,
            if advertised.is_empty() {
                "none"
            } else {

View on GitHub (pinned to 433685b202)