Hmbown/CodeWhale · error
DS4 /v1/models could not be reached at {} (is ds4-server run
Error message
DS4 /v1/models could not be reached at {} (is ds4-server running?) What it means
Same DS4 probe path as [481], but `ds4_probe_error` found no `HTTP <status>` token in the transport error text (doctor.rs:453-456) — the request never got an HTTP response. The doctor concludes the redacted endpoint is unreachable and asks whether ds4-server is running.
Source
Thrown at crates/tui/src/doctor.rs:410
}
/// 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 8880682c63)
Solutions
- Start ds4-server and confirm it listens on the configured port (`ss -ltnp` / `lsof -i` / service status)
- Correct the host and port in `deepseek_base_url`
- Re-run the doctor once the service accepts connections
Defensive patterns
Strategy: validation
Validate before calling
let url = reqwest::Url::parse(&config.deepseek_base_url())?;
let host = url.host_str().context("base URL has no host")?;
let port = url.port_or_known_default().context("no port")?;
tokio::time::timeout(
std::time::Duration::from_secs(3),
tokio::net::TcpStream::connect((host, port)),
).await
.context("ds4-server is not accepting connections")??; Try / catch
match probe_ds4(config).await {
Err(err) if err.to_string().starts_with("DS4 /v1/models could not be reached") => {
eprintln!("start ds4-server, then re-run: {err}");
}
other => other?,
} Prevention
- Order startup so ds4-server is healthy before the doctor runs
- Supervise ds4-server (restart on exit) so silent crashes surface
- Keep the base URL host/port identical across environments
When it happens
Trigger: Nothing is listening on the configured host/port (connection refused); ds4-server is still booting; DNS or routing failure; wrong port in `deepseek_base_url`.
Common situations: Doctor run before ds4-server starts; the service crashed silently; config still pointing at a port from an older install or a different machine.
Related errors
- DS4 /v1/models returned HTTP {status} at {}
- DeepSeek ${res.status}: ${text}
- DS4 /v1/models at {} did not list configured alias '{configu
- Request timeout after 15 seconds
- Could not inspect GitHub Release ${tag}: ${detail}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/4e9b0343b32b8d61.
Report an issue: GitHub.