libnyanpasu/clash-nyanpasu · error

effect function failed: {error:#?}

Error message

effect function failed: {error:#?}

What it means

In with_pending_state_if_version, the conditional effect callback returned an error after the state transaction was prepared. The coordinator rolls back the pending state (RollbackReason::CoordinatorError) and surfaces ConditionalEffectError::Effect so the state remains consistent.

Source

Thrown at backend/nyanpasu-core/src/state/coordinator.rs:262

        };
        let tx = new_transaction(
            change,
            self.current_state.clone(),
            subscribers,
            notify_strategy,
            permit,
        );
        let tx = match tx.prepare().await {
            Ok((_report, prepared_tx)) => prepared_tx,
            Err(err) => {
                let (report, _) = *err;
                return Err(ConditionalEffectError::State(
                    StateChangedError::PrepareAck(PrepareAckError { report }),
                ));
            }
        };
        if let Err(error) = effect_fn(new_state).await {
            tx.rollback(RollbackReason::CoordinatorError(Arc::new(anyhow!(
                "effect function failed: {error:#?}"
            ))))
            .await;
            return Err(ConditionalEffectError::Effect(error));
        }
        match tx.try_commit() {
            Ok(committed_tx) => {
                committed_tx.notify_committed().await;
                self.mark_change_id_committed(next_changed_id);
                Ok(())
            }
            Err(commit_mismatch) => {
                let actual = self.sync_change_id_after_cas_mismatch();
                let commit_error = StateChangedError::StateCasMismatch {
                    expected: current_state.version,
                    actual,
                };
                let committed = self.snapshot_versioned();

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Inspect the nested error ({error:#?}) — the root cause is inside the effect function, not the coordinator.
  2. Make the effect idempotent and retry the whole with_pending_state_if_version call after the cause is fixed.
  3. Return a typed, narrow error from effect_fn to make diagnostics actionable.
  4. If the effect is best-effort, catch its error inside effect_fn and log instead of failing the transaction.

Example fix

// before
.with_pending_state_if_version(ver, |state| async {
    write_runtime_config(state)?;
    Ok(())
})
// after
.with_pending_state_if_version(ver, |state| async {
    match write_runtime_config(state).await {
        Ok(()) => Ok(()),
        Err(e) => {
            log::warn!("best-effort config write failed: {e}");
            Ok(()) // don't roll back state for best-effort effects
        }
    }
})
Defensive patterns

Strategy: retry

Validate before calling

// validate effect preconditions before entering the transaction
async fn effect_safe(state: &State) -> bool {
    state.runtime_config_path.is_writable() && core_reachable().await
}

Try / catch

match coordinator.with_pending_state_if_version(ver, effect_fn).await {
    Err(ConditionalEffectError::Effect(e)) => {
        log::error!("effect failed, state rolled back: {e:#}");
        // safe to retry after fixing the cause
    }
    Err(e) => return Err(e.into()),
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Calling with_pending_state_if_version with an effect_fn that fails (I/O, config write, validation) while a state version transition was pending — e.g. a Tauri-side commit whose post-commit effect could not complete.

Common situations: Effect functions writing runtime config or notifying the core hitting transient failures (core restarting, file locked), or bugs/panics in effect logic.

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


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