Zackriya-Solutions/meetily · error · anyhow::Error
Request timed out after {:?}
Error message
Request timed out after {:?} What it means
send_request enforces a caller-supplied timeout over the whole round trip (write to stdin + read of the response line). On expiry it deliberately shuts the sidecar down to stop token generation, then returns this error - so a timeout also invalidates the process for subsequent requests.
Source
Thrown at frontend/src-tauri/src/summary/summary_engine/sidecar.rs:387
.await
.context("Failed to write newline")?;
stdin.flush().await.context("Failed to flush stdin")?;
}
// Read response from stdout with timeout
match tokio::time::timeout(timeout, self.read_response()).await {
Ok(Ok(response)) => {
self.update_activity().await;
Ok(response)
}
Ok(Err(e)) => Err(e),
Err(_) => {
// Timeout reached - shutdown sidecar to stop generation
log::error!("Request timeout after {:?}, shutting down sidecar", timeout);
if let Err(shutdown_err) = self.shutdown().await {
log::error!("Failed to shutdown sidecar after timeout: {}", shutdown_err);
}
Err(anyhow!("Request timed out after {:?}", timeout))
}
}
}
/// Read a single line response from stdout
async fn read_response(&self) -> Result<String> {
let mut stdout_lock = self.stdout_reader.lock().await;
let reader = stdout_lock
.as_mut()
.ok_or_else(|| anyhow!("Sidecar not running"))?;
let mut line = String::new();
reader
.read_line(&mut line)
.await
.context("Failed to read response from stdout")?;
if line.is_empty() {View on GitHub (pinned to 0281737d87)
Solutions
- Increase the timeout passed to send_request for summary workloads - CPU inference on a large model can take minutes
- Switch to a smaller/faster summary model from the catalog
- Shorten the prompt (truncate or chunk the transcript) before summarizing
- Treat the error as non-retryable as-is: the sidecar is dead, so call ensure_running before the next request
Defensive patterns
Strategy: retry
Validate before calling
// Size the timeout to the workload instead of a fixed constant
let est_tokens = transcript_len / 4; // rough token estimate
let timeout = Duration::from_secs(
(30 + est_tokens / tokens_per_second(model)).max(120).max(previous_timeout),
); Try / catch
let mut attempt = 0;
loop {
match sidecar.send_request(req.clone(), timeout).await {
Err(e) if e.to_string().contains("timed out") && attempt < 2 => {
attempt += 1;
sidecar.ensure_running(model_path.clone()).await?; // sidecar was killed on timeout
continue; // optionally with a larger timeout
}
other => break other,
}
}? Prevention
- Remember the timeout path shuts the sidecar down: always respawn before retrying
- Scale timeouts with transcript length and model size; CPU inference is minutes, not seconds
- Run heavy summaries on a smaller model or chunk long transcripts to stay under the ceiling
When it happens
Trigger: LLM inference on the loaded GGUF model takes longer than the passed Duration: long transcripts with a large model on CPU, the machine throttled (the sidecar runs under nice -n 10 on Unix / BELOW_NORMAL_PRIORITY_CLASS on Windows), or a timeout value set too small for the summary workload.
Common situations: First summary after loading a large model on CPU-only machines, hour-long meeting transcripts, contention with whisper transcription or other heavy processes on the same machine.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Generation failed: {}
- VAD processing failed: {}
- Parakeet transcription failed: {}
- Download timeout - No data received for 30 seconds
- Sidecar error: {}
AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16).
Data as JSON: /api/errors/c61163425d7a2614.
Report an issue: GitHub.