{"record":{"id":"e67bb4e85163b7fd","repo":"Zackriya-Solutions/meetily","slug":"sidecar-not-running","errorCode":null,"errorMessage":"Sidecar not running","messagePattern":"Sidecar not running","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"frontend/src-tauri/src/summary/summary_engine/sidecar.rs","lineNumber":361,"sourceCode":"\n        // Start background tasks\n        self.start_health_check_loop();\n        self.start_idle_check_loop();\n\n        Ok(())\n    }\n\n    /// Send a request to the sidecar and wait for response\n    pub async fn send_request(&self, request_json: String, timeout: Duration) -> Result<String> {\n        // Track active request\n        let _guard = RequestGuard::new(self.active_request_count.clone());\n\n        // Write request to stdin\n        {\n            let mut stdin_lock = self.stdin_writer.lock().await;\n            let stdin = stdin_lock\n                .as_mut()\n                .ok_or_else(|| anyhow!(\"Sidecar not running\"))?;\n\n            stdin\n                .write_all(request_json.as_bytes())\n                .await\n                .context(\"Failed to write request to stdin\")?;\n            stdin\n                .write_all(b\"\\n\")\n                .await\n                .context(\"Failed to write newline\")?;\n            stdin.flush().await.context(\"Failed to flush stdin\")?;\n        }\n\n        // Read response from stdout with timeout\n        match tokio::time::timeout(timeout, self.read_response()).await {\n            Ok(Ok(response)) => {\n                self.update_activity().await;\n                Ok(response)\n            }","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/Zackriya-Solutions/meetily/blob/0281737d87d26352fb0adc78c8c0975f691b23d1/frontend/src-tauri/src/summary/summary_engine/sidecar.rs#L343-L379","documentation":"send_request writes a JSON line to the sidecar's stdin, but stdin_writer is None when no sidecar process is attached. That happens when send_request runs before ensure_running()/spawn() completes, or after shutdown() - including the automatic shutdown performed by the timeout path in send_request itself.","triggerScenarios":"Calling send_request without a prior successful ensure_running(model_path); sending a follow-up request after a previous request timed out (the timeout branch calls shutdown() and clears handles); a race where one task shuts the sidecar down while another is mid-write.","commonSituations":"Retry logic that resubmits after a timeout without respawning; concurrent summarization tasks where one triggers idle-shutdown while another writes; first request after the sidecar's LLAMA_IDLE_TIMEOUT reaped the process.","solutions":["Always pair requests with lifecycle: await ensure_running(&model_path) before send_request - it spawns when unhealthy","After a timeout error, call ensure_running again before retrying (the sidecar was killed by design)","Serialize requests via the existing active_request_count/RequestGuard so shutdown cannot race an in-flight write"],"exampleFix":"// before - send may hit a shut-down sidecar\nlet resp = sidecar.send_request(request_json, timeout).await?;\n\n// after - ensure the process is alive (spawns or respawns as needed)\nsidecar.ensure_running(model_path.clone()).await?;\nlet resp = sidecar.send_request(request_json, timeout).await?;","handlingStrategy":"validation","validationCode":"// Lifecycle gate before every request\nif !sidecar.is_healthy() {\n    sidecar.ensure_running(model_path.clone()).await?;\n}\nlet resp = sidecar.send_request(request_json, timeout).await?;","typeGuard":"// Rust: narrow on the live handle rather than a boolean\npub async fn live_stdin(sidecar: &LlamaHelper) -> bool {\n    sidecar.stdin_writer.read().await.is_some()\n}","tryCatchPattern":"match sidecar.send_request(req, timeout).await {\n    Err(e) if e.to_string().contains(\"Sidecar not running\") => {\n        sidecar.ensure_running(model_path.clone()).await?; // respawn\n        sidecar.send_request(req, timeout).await          // one retry\n    }\n    other => other,\n}","preventionTips":["Never call send_request without a preceding ensure_running in the same task","Treat a timeout error as implicitly destroying the sidecar: the next call must respawn","Serialize requests so shutdown (manual or idle) cannot race an in-flight write"],"tags":["sidecar","lifecycle","stdin","api-misuse"],"backgroundTag":"process-not-running","analyzedSha":"0281737d87d26352fb0adc78c8c0975f691b23d1","analyzedAt":"2026-08-16T20:57:52.567Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}