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
- 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)
- Reset/rebuild the execution snapshot if the intent is already finalized on-chain
- 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
- Persist hash replacement (deactivate old + activate new) atomically
- Ensure single-writer access to the execution store
- Reconcile current-hash flags with on-chain nonce/status during recovery
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
- Retained execution history has multiple active signer owners
- Retained execution intent has an unsupported purpose
- Execution intent {} has a signed transaction {} that was not
- Verification migration was supplied for an initialized signe
- A recoverable execution for wallet {} retains signed transac
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/03065ee09dd3cf2c.
Report an issue: GitHub.