libnyanpasu/clash-nyanpasu · error

application actor reply dropped

Error message

application actor reply dropped

What it means

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.

Source

Thrown at backend/tauri/src/client/application.rs:113

        self.replace_prepared_if_version(expected_version, prepared)
            .await
    }

    pub(crate) async fn prepare_replace(
        &self,
        state: NyanpasuAppConfig,
    ) -> anyhow::Result<PreparedTypedReplace<NyanpasuAppConfig>> {
        match self
            .inner
            .actor_ref
            .call(
                |reply| ApplicationActorMessage::PrepareReplace { state, reply },
                None,
            )
            .await?
        {
            CallResult::Success(result) => result,
            CallResult::SenderError => anyhow::bail!("application actor reply dropped"),
            CallResult::Timeout => anyhow::bail!("application actor call timed out"),
        }
    }

    pub(crate) async fn replace_prepared_if_version(
        &self,
        expected_version: u64,
        prepared: PreparedTypedReplace<NyanpasuAppConfig>,
    ) -> anyhow::Result<ConditionalReplaceResult<ApplicationSnapshot>> {
        match self
            .inner
            .actor_ref
            .call(
                |reply| ApplicationActorMessage::ReplacePreparedIfVersion {
                    expected_version,
                    prepared,
                    reply,
                },

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Retry the replacement after confirming the application actor is running
  2. Check actor startup/supervision logs for shutdown at the time of the call
  3. Ensure the actor handler always replies to PrepareReplace, including on error paths
Defensive patterns

Strategy: retry

Validate before calling

if !app_client.is_actor_alive().await {
  return Err(anyhow::anyhow!("application actor not running; skip replace"));
}

Try / catch

match prepare_replace(state).await {
  Ok(result) => result,
  Err(e) if e.to_string().contains("reply dropped") => {
    // actor likely shutting down; retry once after re-checking liveness
    retry_prepare_replace(state).await
  }
  Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: 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.

Common situations: App version replacement raced with shutdown/restart, or actor supervision tore down the state actor mid-call.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/b5d57996774483c6. Report an issue: GitHub.