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

  1. Increase the timeout passed to send_request for summary workloads - CPU inference on a large model can take minutes
  2. Switch to a smaller/faster summary model from the catalog
  3. Shorten the prompt (truncate or chunk the transcript) before summarizing
  4. 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

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

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16). Data as JSON: /api/errors/c61163425d7a2614. Report an issue: GitHub.