Hmbown/CodeWhale · error
DS4 /v1/models timed out after 15 seconds at
Error message
DS4 /v1/models timed out after 15 seconds at {} What it means
In `probe_ds4_models`, the `list_models` call is wrapped in a 15-second timeout via `tokio::time::timeout`. When the future does not complete in time (the `Err(_)` arm), the probe bails with a timeout message naming the endpoint. The endpoint answered too slowly or not at all.
Solutions
- Confirm the endpoint is responsive with `curl --max-time 15 <endpoint>/v1/models` and restart the DS4 server if it hangs.
- Check network/firewall rules between this machine and the DS4 endpoint.
- Verify DNS resolves the endpoint host to the correct reachable address.
- If the endpoint is genuinely slow, reduce load or move it closer; the 15-second probe budget is fixed.
Defensive patterns
Strategy: retry
Validate before calling
curl -sS --max-time 15 "$DS4_ENDPOINT/v1/models" >/dev/null && echo reachable || echo unreachable
Try / catch
for attempt in 0..3 {
match probe_ds4_models().await {
Err(e) if e.to_string().contains("timed out") => tokio::time::sleep(Duration::from_secs(2u64.pow(attempt))).await,
other => { other?; break; }
}
} Prevention
- Confirm network/firewall paths to the DS4 endpoint before automation runs.
- Monitor DS4 server load; restart or scale when latency grows.
- Avoid DNS black holes: verify the host resolves to a reachable address.
When it happens
Trigger: Doctor DS4 probe where `client.list_models()` takes longer than 15 seconds — hung connection, unresponsive server, or network black hole (packets dropped rather than refused).
Common situations: DS4 server overloaded or stuck; firewall silently dropping traffic to the endpoint; DNS resolving to an unreachable host; remote endpoint with very high latency.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- DS4 /v1/models could not be reached at
- ds4_probe_error(config, &error.to_string())
- DS4 /v1/models at did not list configured alias ' '…
- DS4 /v1/models returned HTTP
- GET timeout
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/7dc555bf7a4369da.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/doctor.rs:580
/// 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::CodewhaleClient;
use crate::core::model_client::ModelClient;
let endpoint = crate::client::redact_url_for_display(&config.active_route_base_url());
let client = CodewhaleClient::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 73e0f67d83)