tonhowtf/omniget · error · anyhow::Error

Timeout downloading segment

Error message

Timeout downloading segment

What it means

Raised in download_segment_with_retry when the per-attempt tokio::time::timeout around the segment request elapses before the response completes. The join/timeout wrapper returns Err(_), and the loop records this generic 'Timeout downloading segment' error and continues retrying with backoff until attempts are exhausted.

Solutions

  1. Increase the per-segment timeout to accommodate the largest expected segment at the target bitrate.
  2. Rely on the retry loop — transient stalls usually succeed on a later attempt.
  3. Enable HTTP range/resumable downloads for large segments instead of fetching in one request.
  4. Check network stability; a connection that repeatedly times out indicates a local or ISP issue.

Example fix

// before
Err(_) => last_err = Some(anyhow::anyhow!("Timeout downloading segment")),
// after
Err(_) => last_err = Some(anyhow::anyhow!(
    "Timeout downloading segment {} after {}ms (attempt {}/{})",
    seg_url, timeout_ms, attempt + 1, max_retries
)),
Defensive patterns

Strategy: retry

Validate before calling

// sanity-check the timeout budget against expected segment size and bandwidth
let expected_secs = (max_segment_bytes as f64 / min_bandwidth_bps as f64 * 8.0) as u64;
if timeout.as_secs() < expected_secs {
    log::warn!("segment timeout {}s likely too small; expect ~{}s", timeout.as_secs(), expected_secs);
}

Try / catch

match tokio::time::timeout(timeout, download_once(url)).await {
    Err(_) => {
        last_err = Some(anyhow::anyhow!("Timeout downloading segment (attempt {}/{})", attempt + 1, max_retries));
        continue; // retry with backoff
    }
    Ok(inner) => inner?,
}

Prevention

When it happens

Trigger: A single segment request exceeds the configured per-segment timeout duration — slow/throttled CDN, huge segment on a poor connection, or a hung connection that never sends the body.

Common situations: Downloading over congested Wi-Fi/mobile networks; CDN throttling per-connection throughput; very long segments (e.g., 10s+ 1080p chunks) exceeding a tight timeout; server accepting the connection but stalling the body.

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.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/d070d0dcc9d30cba. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/hls_downloader.rs:748

                return Err(anyhow::anyhow!("HTTP {} downloading segment", code));
            }

            resp.bytes()
                .await
                .map(|b| b.to_vec())
                .map_err(|e| anyhow::anyhow!(e))
        })
        .await;

        match result {
            Ok(Ok(data)) => return Ok(data),
            Ok(Err(e)) => {
                if e.to_string().contains("(fatal)") {
                    return Err(e);
                }
                last_err = Some(e);
            }
            Err(_) => last_err = Some(anyhow::anyhow!("Timeout downloading segment")),
        }
        if attempt < max_retries - 1 {
            let base = 500 * (attempt as u64 + 1);
            let jitter = rand::random::<u64>() % (base / 2 + 1);
            tokio::time::sleep(std::time::Duration::from_millis(base + jitter)).await;
        }
    }
    Err(last_err.unwrap_or_else(|| {
        anyhow::anyhow!("Segment download failed after {} attempts", max_retries)
    }))
}

const PNG_SIGNATURE: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
const JPEG_SIGNATURE: [u8; 3] = [0xFF, 0xD8, 0xFF];

/// Number of leading bytes to drop from a segment that arrived disguised as an
/// image.
///

View on GitHub (pinned to 8600b91f42)