{"record":{"id":"762da8a0de33d5b7","repo":"libnyanpasu/clash-nyanpasu","slug":"proxy-actor-is-unavailable","errorCode":null,"errorMessage":"proxy actor is unavailable","messagePattern":"proxy actor is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/core/proxies.rs","lineNumber":331,"sourceCode":"            snapshots: snapshot_rx,\n            changes: changes_rx,\n        })))\n    }\n    async fn call<T: Send + 'static>(\n        &self,\n        message: impl FnOnce(RpcReplyPort<Result<T>>) -> Message,\n    ) -> Result<T> {\n        match self\n            .0\n            .actor\n            .call(message, Some(Duration::from_secs(120)))\n            .await\n        {\n            Ok(ractor::rpc::CallResult::Success(result)) => result,\n            Ok(ractor::rpc::CallResult::Timeout) => anyhow::bail!(\n                \"proxy actor timed out; an operation may still be running, do not replay mutations automatically\"\n            ),\n            _ => anyhow::bail!(\"proxy actor is unavailable\"),\n        }\n    }\n    pub async fn get(&self, force: bool) -> Result<Proxies> {\n        let snapshot = self.call(|reply| Message::Read { force, reply }).await?;\n        anyhow::ensure!(\n            !snapshot.api.is_revoked(),\n            \"proxy snapshot belongs to a retired instance\"\n        );\n        Ok(snapshot.proxies.clone())\n    }\n    pub async fn providers(&self) -> Result<api::ProvidersProxiesRes> {\n        let snapshot = self\n            .call(|reply| Message::Read {\n                force: false,\n                reply,\n            })\n            .await?;\n        anyhow::ensure!(","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/core/proxies.rs#L313-L349","documentation":"Thrown by the proxies service `call` helper when a request to the proxy actor fails for any reason other than success or timeout — typically because the actor is not running, has crashed, or its mailbox/channel is unavailable. Unlike the timeout case, the operation is definitively not in flight, so calls fail fast. Callers of `get`, `providers`, `select`, and `update_provider` all funnel through this error when the actor layer is down.","triggerScenarios":"Any of `get`, `providers`, `select`, or `update_provider` calling `call(...)` when `actor.call(...)` returns an `Err` (send failure / dead actor) or a `CallResult` other than `Success`/`Timeout`, e.g. the actor was never spawned or was stopped during supervision shutdown.","commonSituations":"The app is shutting down and the actor was stopped mid-request; actor startup failed at bootstrap so the client holds a dead `ActorRef`; a supervision/crash took the actor down; calling the client before `NyanpasuClient` bootstrap finished.","solutions":["Restart the application (or the actor via the app's restart path) so the proxy actor is respawned and the client gets a live reference.","Ensure `NyanpasuClient`/`AppSupervisor` bootstrap completed before issuing proxy operations; check startup logs for actor spawn failures.","If shutdown races cause it, add graceful shutdown ordering so stop signals wait for in-flight proxy calls to drain."],"exampleFix":"// before: calling proxies API during/after shutdown\nlet proxies = client.get_proxies().await?; // actor already stopped\n\n// after: ensure bootstrap/actor liveness before use\nif client.is_ready().await {\n    let proxies = client.get_proxies().await?;\n} else {\n    anyhow::bail!(\"proxy actor not started; complete bootstrap first\");\n}","handlingStrategy":"fallback","validationCode":"// Check client/actor readiness before issuing proxy calls\nif !client.is_ready().await {\n    eprintln!(\"proxy actor unavailable: complete bootstrap before calling proxies API\");\n}","typeGuard":null,"tryCatchPattern":"match client.get_proxies().await {\n    Err(e) if e.to_string().contains(\"proxy actor is unavailable\") => {\n        // actor dead — restart app/core; do not spam retries\n        eprintln!(\"restarting core to recover proxy actor\");\n        client.restart_core().await?;\n    }\n    other => other?,\n}","preventionTips":["Ensure NyanpasuClient bootstrap fully completes before exposing proxy APIs to the UI","Check startup logs for actor spawn failures after upgrades","Order shutdown so in-flight proxy RPCs drain before stopping the actor","Treat this as non-retryable per-attempt: recover by restarting the actor/core, not re-sending"],"tags":["actor","proxy","lifecycle","availability"],"backgroundTag":"connection-refused","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}