libnyanpasu/clash-nyanpasu · warning
proxy snapshot belongs to a retired instance
Error message
proxy snapshot belongs to a retired instance
What it means
ProxiesClient::get requests a proxy snapshot from the proxies actor via an RPC message. The returned snapshot carries an `api` handle to the mihomo/clash external controller instance; if that instance has since been revoked (core restarted/replaced, actor re-initialized), the snapshot is stale and the client refuses to return it. This is a staleness guard ensuring callers never see proxy data from a dead core instance.
Source
Thrown at backend/tauri/src/core/proxies.rs:336
&self,
message: impl FnOnce(RpcReplyPort<Result<T>>) -> Message,
) -> Result<T> {
match self
.0
.actor
.call(message, Some(Duration::from_secs(120)))
.await
{
Ok(ractor::rpc::CallResult::Success(result)) => result,
Ok(ractor::rpc::CallResult::Timeout) => anyhow::bail!(
"proxy actor timed out; an operation may still be running, do not replay mutations automatically"
),
_ => anyhow::bail!("proxy actor is unavailable"),
}
}
pub async fn get(&self, force: bool) -> Result<Proxies> {
let snapshot = self.call(|reply| Message::Read { force, reply }).await?;
anyhow::ensure!(
!snapshot.api.is_revoked(),
"proxy snapshot belongs to a retired instance"
);
Ok(snapshot.proxies.clone())
}
pub async fn providers(&self) -> Result<api::ProvidersProxiesRes> {
let snapshot = self
.call(|reply| Message::Read {
force: false,
reply,
})
.await?;
anyhow::ensure!(
!snapshot.api.is_revoked(),
"provider snapshot belongs to a retired instance"
);
Ok(snapshot.providers.clone())
}View on GitHub (pinned to f7dbce2997)
Solutions
- Retry the call after a short delay so the actor refreshes its snapshot with the new core instance
- Restart or re-select the core so the proxies actor re-binds to a live API before reading proxies
- Handle this error in the UI as a transient state and re-fetch after core readiness signals
Example fix
// before
let proxies = proxies_client.get(false).await?;
// after
let proxies = match proxies_client.get(false).await {
Ok(p) => p,
Err(e) if e.to_string().contains("retired instance") => {
tokio::time::sleep(Duration::from_millis(500)).await;
proxies_client.get(true).await?
}
Err(e) => return Err(e),
}; Defensive patterns
Strategy: retry
Validate before calling
// caller-side staleness check is not possible before the call; instead guard the retry
let proxies = loop {
match client.get(false).await {
Ok(p) => break p,
Err(e) if e.to_string().contains("retired instance") => tokio::time::sleep(Duration::from_millis(500)).await,
Err(e) => return Err(e),
}
}; Try / catch
match proxies_client.get(force).await {
Ok(p) => p,
Err(e) if e.to_string().contains("retired instance") => /* transient: wait for core ready, then retry */,
Err(e) => return Err(e),
} Prevention
- Subscribe to core-restart events and refresh proxy data only after the new API handle is live
- Add bounded retry with backoff around proxy reads during core lifecycle transitions
- Avoid reading proxies concurrently with core switch/restart operations
When it happens
Trigger: Calling `client.proxies().get(force)` after the core process was restarted or replaced, or while the proxies actor is re-initializing its API handle; the actor replies with a cached snapshot whose embedded api handle reports is_revoked() == true.
Common situations: Core switch (mihomo <-> clash-rs), core crash and auto-restart, config reload that recreates the external controller, or a UI refresh racing a core restart.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- provider snapshot belongs to a retired instance
- application actor call timed out
- clash config actor reply dropped
- clash config actor call timed out
- session state actor reply dropped
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/9217d162835ade55.
Report an issue: GitHub.