nautechsystems/nautilus_trader · error
Unowned replacement hash retains signed bytes
Error message
Unowned replacement hash retains signed bytes
What it means
When replaying retained hashes, a replacement hash that the current client cannot authenticate as its own (not owned by this signer) must carry no signed bytes (raw_transaction / sealed_transaction). This error is thrown if an unowned replacement hash still stores signed transaction bytes, which would be a security risk — signed bytes for another owner should never be retained or replayed.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:5374
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",
)?;
authenticated.insert(hash.id, raw);
} else {
anyhow::ensure!(
hash.raw_transaction.is_none() && hash.sealed_transaction.is_none(),
"Unowned replacement hash retains signed bytes"
);
}
}
if let Some(nonce) = intent.nonce {
anyhow::ensure!(
nonce_owners.insert(nonce, intent.id).is_none(),
"Retained execution history has duplicate signer nonce ownership"
);
}
let base_decision = verification_decision(
nonce_verification,
Some(finalized.number),
Some(finalized.number),
);View on GitHub (pinned to 18893faf8b)
Solutions
- Purge the offending snapshot (or strip raw_transaction/sealed_transaction from unowned hashes) and rebuild execution state
- Upgrade/downgrade to the client version that authored the snapshot so ownership verification can authenticate the hashes
- Never share durable execution stores between wallets; keep signed bytes encrypted and scoped per signer
Defensive patterns
Strategy: validation
Validate before calling
fn no_signed_bytes_on_unowned(hashes: &[HashRecord], wallet: Address) -> bool {
hashes.iter().filter(|h| !owned_by(h, wallet))
.all(|h| h.raw_transaction.is_none() && h.sealed_transaction.is_none())
} Try / catch
match client.start_with_snapshot(snapshot) {
Err(e) if e.to_string().contains("retains signed bytes") => { /* quarantine store, strip signed bytes from unowned hashes, rebuild */ }
other => other?,
} Prevention
- Never share execution stores across wallets
- Encrypt and scope signed transaction bytes to a single signer
- Run snapshot integrity checks (ownership + signed-bytes policy) before loading
When it happens
Trigger: Recovery encounters hash.current intent whose owner check fails (verification migration path not taken) while hash.raw_transaction or hash.sealed_transaction is Some.
Common situations: Snapshot copied from another deployment/wallet that includes signed raw transactions; a version that persisted signed bytes for replacement hashes before this ownership rule existed; store corruption or tampering.
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
- Retained execution intent {} has multiple current hashes
- old user stream dispatch task failed: {error}
- old user stream dispatch task did not stop after abort
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/bcb7481cf90cccfb.
Report an issue: GitHub.