{"record":{"id":"b5d57996774483c6","repo":"libnyanpasu/clash-nyanpasu","slug":"application-actor-reply-dropped","errorCode":null,"errorMessage":"application actor reply dropped","messagePattern":"application actor reply dropped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/client/application.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: NyanpasuAppConfig,\n    ) -> anyhow::Result<PreparedTypedReplace<NyanpasuAppConfig>> {\n        match self\n            .inner\n            .actor_ref\n            .call(\n                |reply| ApplicationActorMessage::PrepareReplace { state, reply },\n                None,\n            )\n            .await?\n        {\n            CallResult::Success(result) => result,\n            CallResult::SenderError => anyhow::bail!(\"application actor reply dropped\"),\n            CallResult::Timeout => anyhow::bail!(\"application 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<NyanpasuAppConfig>,\n    ) -> anyhow::Result<ConditionalReplaceResult<ApplicationSnapshot>> {\n        match self\n            .inner\n            .actor_ref\n            .call(\n                |reply| ApplicationActorMessage::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/application.rs#L95-L131","documentation":"ApplicationClient.prepare_replace sends a PrepareReplace RPC with a reply port to the application actor; if the call returns CallResult::SenderError the reply port was dropped without an answer, surfaced as 'application actor reply dropped'. This typically means the actor is shutting down or its handler failed to reply.","triggerScenarios":"replace_if_version calling prepare_replace while the application actor is stopping, has crashed, or its message handler dropped the RpcReplyPort without sending a result.","commonSituations":"App version replacement raced with shutdown/restart, or actor supervision tore down the state actor mid-call.","solutions":["Retry the replacement after confirming the application actor is running","Check actor startup/supervision logs for shutdown at the time of the call","Ensure the actor handler always replies to PrepareReplace, including on error paths"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if !app_client.is_actor_alive().await {\n  return Err(anyhow::anyhow!(\"application actor not running; skip replace\"));\n}","typeGuard":null,"tryCatchPattern":"match prepare_replace(state).await {\n  Ok(result) => result,\n  Err(e) if e.to_string().contains(\"reply dropped\") => {\n    // actor likely shutting down; retry once after re-checking liveness\n    retry_prepare_replace(state).await\n  }\n  Err(e) => return Err(e),\n}","preventionTips":["Ensure every actor handler replies to RPC ports on all paths","Avoid issuing RPCs during shutdown/restart windows","Use finite timeouts and treat SenderError as retryable-after-liveness-check"],"tags":["ractor","actor","ipc","shutdown"],"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"}