nautechsystems/nautilus_trader · error

Retained execution intent {} has multiple current hashes

Error message

Retained execution intent {} has multiple current hashes

What it means

For each retained intent, the client collects hashes flagged as current; exactly one hash may be the current transaction for an intent. Multiple current hashes mean the persisted state is ambiguous (e.g. a replacement was recorded without clearing the previous hash), so recovery aborts with the intent ID in the message.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:5353

        for intent in &snapshot.intents {
            anyhow::ensure!(
                intent.chain_id == self.chain.chain_id
                    && intent.wallet_address == self.config.wallet_address,
                "Retained execution intent belongs to another signer"
            );
            let purpose = TransactionPurpose::parse(&intent.purpose).ok_or_else(|| {
                anyhow::anyhow!("Retained execution intent has an unsupported purpose")
            })?;
            let hashes = hashes_by_intent
                .get(&intent.id)
                .map(Vec::as_slice)
                .unwrap_or_default();
            let current = hashes
                .iter()
                .copied()
                .filter(|hash| hash.current)
                .collect::<Vec<_>>();
            anyhow::ensure!(
                current.len() <= 1,
                "Retained execution intent {} has multiple current hashes",
                intent.id
            );
            let current = current.first().copied();
            let mut authenticated = HashMap::new();

            for hash in hashes {
                if hash.payload_expected {
                    let raw = open_execution_payload(
                        self.payload_keys
                            .as_deref()
                            .expect("Postgres execution requires payload keys"),
                        self.payload_policy(),
                        intent,
                        hash,
                        "verification migration",
                    )?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Stop writers, inspect the snapshot for the offending intent ID, and mark all but the latest hash as non-current (verify on-chain which tx is actually live)
  2. Reset/rebuild the execution snapshot if the intent is already finalized on-chain
  3. Make hash-replacement persistence atomic (single transaction deactivating the old and activating the new)
Defensive patterns

Strategy: try-catch

Validate before calling

fn current_hashes_unambiguous(snapshot: &ExecutionSnapshot, hashes_by_intent: &HashMap<Uuid, Vec<HashRecord>>) -> Result<(), String> {
    for intent in &snapshot.intents {
        let n = hashes_by_intent.get(&intent.id).map(|h| h.iter().filter(|x| x.current).count()).unwrap_or(0);
        if n > 1 { return Err(format!("intent {} has {n} current hashes", intent.id)); }
    }
    Ok(())
}

Try / catch

match client.start_with_snapshot(snapshot) {
    Err(e) if e.to_string().contains("multiple current hashes") => { /* reconcile with chain, mark only the live tx current, retry */ }
    other => other?,
}

Prevention

When it happens

Trigger: Recovering execution state where snapshot.intents[i] has two or more associated transaction hashes with hash.current == true.

Common situations: A crash mid-replacement (new hash written before old one was marked non-current) with non-atomic persistence; concurrent writers replacing the same intent; store corruption.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/03065ee09dd3cf2c. Report an issue: GitHub.