Hmbown/CodeWhale · warning · anyhow::Error
DS4 /v1/models timed out after 15 seconds at {}
Error message
DS4 /v1/models timed out after 15 seconds at {} What it means
Thrown by probe_ds4_models when the tokio::time::timeout wrapper around client.list_models() elapses after 15 seconds without a result. The endpoint (redacted) is included so you can tell which base URL hung.
Source
Thrown at crates/tui/src/doctor.rs:584
/// 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 {
advertised.as_str()View on GitHub (pinned to 0c42157ee5)
Solutions
- Check ds4-server health and restart it if it is wedged
- Confirm the network path (local vs remote endpoint) responds; try curl with a manual timeout
- Retry the doctor probe once the server is idle
Defensive patterns
Strategy: retry
Try / catch
const ATTEMPTS: usize = 2;
for attempt in 1..=ATTEMPTS {
match probe_ds4_models(&config).await {
Ok(()) => break,
Err(error) if attempt < ATTEMPTS && error.to_string().contains("timed out") => {
tokio::time::sleep(std::time::Duration::from_secs(2 * attempt as u64)).await;
}
Err(error) => return Err(error),
}
} Prevention
- Check ds4-server load before probing; a server busy loading a model will not answer in 15s
- Keep the probe on a local network path when possible; the 15s budget assumes low latency
- Treat repeated timeouts as a wedged server: restart it rather than retrying indefinitely
When it happens
Trigger: ds4-server accepting the TCP connection but never answering /v1/models within 15s: an overloaded or wedged server, a stalled proxy, or a blackholed route.
Common situations: ds4-server busy loading a model; slow reverse proxy; network path with high latency or packet loss; server deadlocked after a crash-loop.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- DS4 /v1/models returned HTTP {status} at {}
- DS4 /v1/models could not be reached at {} (is ds4-server run
- DS4 /v1/models at {} did not list configured alias '{configu
- Request timeout after 15 seconds
- terminal input pump did not pause before launching editor
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/7dc555bf7a4369da.
Report an issue: GitHub.