{"record":{"id":"5bf5d26084fbe4c4","repo":"libnyanpasu/clash-nyanpasu","slug":"session-state-actor-reply-dropped","errorCode":null,"errorMessage":"session state actor reply dropped","messagePattern":"session state actor reply dropped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/client/session_state.rs","lineNumber":113,"sourceCode":"        self.replace_prepared_if_version(expected_version, prepared)\n            .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                },","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/client/session_state.rs#L95-L131","documentation":"Raised in SessionStateClient::prepare_replace (backend/tauri/src/client/session_state.rs:113) when the ractor RPC for SessionStateActorMessage::PrepareReplace returns CallResult::SenderError, meaning the actor dropped the reply sender without answering — typically because the actor was stopped, panicked, or its handler failed before replying.","triggerScenarios":"replace_if_version calls prepare_replace; the actor_ref.call resolves to CallResult::SenderError, i.e. the RpcReplyPort was dropped by the session-state actor side without sending a result.","commonSituations":"Session-state actor stopped during shutdown while a client still issues prepare_replace; actor handler panicked mid-prepare; actor was never spawned and the message landed nowhere that replies.","solutions":["Confirm the SessionStateActor is running (not stopped) before issuing prepare_replace.","Retry the operation; if it follows an actor stop, recreate the client/actor pair.","Check actor handler logs for panics or early returns that skip the reply.","Ensure client Drop ordering does not stop the actor while other holders still call it."],"exampleFix":"// before\nlet prepared = client.prepare_replace(state).await?; // may hit dropped reply during shutdown\n// after\nif client.is_running().await {\n    let prepared = client.prepare_replace(state).await?;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.prepare_replace(state).await {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"reply dropped\") => {\n        // actor likely stopped: respawn/rebind, then retry once\n        let client = supervisor.rebind_session_state().await?;\n        client.prepare_replace(state).await?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Serialize actor shutdown so stop happens only after in-flight client calls drain","Check handler code paths for early returns that skip the RpcReplyPort send","Wrap actor handlers so panics are caught and answered with an error reply","Re-read state after a dropped-reply error before retrying writes"],"tags":["actor","rpc","rust","ipc"],"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"}