{"record":{"id":"05e86ee3f976759b","repo":"libnyanpasu/clash-nyanpasu","slug":"session-state-actor-call-timed-out","errorCode":null,"errorMessage":"session state actor call timed out","messagePattern":"session state actor call timed out","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/client/session_state.rs","lineNumber":114,"sourceCode":"            .await\n    }\n\n    pub(crate) async fn prepare_replace(\n        &self,\n        state: PersistentState,\n    ) -> anyhow::Result<PreparedTypedReplace<PersistentState>> {\n        match self\n            .inner\n            .actor_ref\n            .call(\n                |reply| SessionStateActorMessage::PrepareReplace { state, reply },\n                None,\n            )\n            .await?\n        {\n            CallResult::Success(result) => result,\n            CallResult::SenderError => anyhow::bail!(\"session state actor reply dropped\"),\n            CallResult::Timeout => anyhow::bail!(\"session state actor call timed out\"),\n        }\n    }\n\n    pub(crate) async fn replace_prepared_if_version(\n        &self,\n        expected_version: u64,\n        prepared: PreparedTypedReplace<PersistentState>,\n    ) -> anyhow::Result<ConditionalReplaceResult<SessionStateSnapshot>> {\n        match self\n            .inner\n            .actor_ref\n            .call(\n                |reply| SessionStateActorMessage::ReplacePreparedIfVersion {\n                    expected_version,\n                    prepared,\n                    reply,\n                },\n                None,","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/client/session_state.rs#L96-L132","documentation":"Raised in SessionStateClient::prepare_replace (backend/tauri/src/client/session_state.rs:114) when the PrepareReplace RPC times out (CallResult::Timeout): the session-state actor did not answer within the allotted (or default) timeout. Points to a busy, blocked, or deadlocked actor rather than a dropped reply.","triggerScenarios":"replace_if_version calls prepare_replace; actor_ref.call returns CallResult::Timeout because the actor never sent on the RpcReplyPort in time — e.g. it is stuck on slow persistence or queued behind many messages.","commonSituations":"Actor mailbox flooded with updates; prepare does synchronous disk I/O on a slow filesystem; synchronous cross-actor cycle stalling the handler; caller timeout set far below realistic handler latency.","solutions":["Retry once; transient queueing is the most common cause.","Increase the timeout for prepare_replace calls.","Audit the PrepareReplace handler for blocking I/O or synchronous calls into other actors (possible deadlock) and make it async/non-blocking.","Check actor logs and mailbox depth to confirm overload and add backpressure upstream."],"exampleFix":"// before\nclient.prepare_replace(state).await?; // default/short timeout\n// after\nclient.prepare_replace_with_timeout(state, Duration::from_secs(10)).await?;","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.prepare_replace(state).await {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"call timed out\") => {\n        tokio::time::sleep(Duration::from_millis(250)).await;\n        client.prepare_replace(state).await? // retry once\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Give prepare_replace a timeout sized for worst-case persistence latency","Keep the PrepareReplace handler non-blocking (spawn_blocking for fsync-heavy work)","Avoid synchronous cross-actor calls from the session-state handler","Add a liveness probe (cheap get) before long config operations"],"tags":["actor","timeout","rpc","rust"],"backgroundTag":"request-timeout","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"}