nautechsystems/nautilus_trader · error · anyhow::Error

Execution intent {intent_id} has no current hash

Error message

Execution intent {intent_id} has no current hash

What it means

current_execution_hash() filters a reconciliation-loaded intent's transaction-hash history for the row flagged current = TRUE and found none. Every intent past the prepared/signed stage must have exactly one current hash (the hash reconciliation should track), so the table invariant is broken and the intent cannot be replayed.

Source

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

            stable_head.hash == head.hash,
            "Canonical head changed during signer-nonce replacement scan"
        );
        Ok(found)
    }

    fn release_slot(&self) {
        *self.in_flight.lock().expect("in-flight mutex poisoned") = None;
    }
}

fn current_execution_hash(
    intent_id: i64,
    hashes: &[ExecutionTransactionHashRow],
) -> anyhow::Result<&ExecutionTransactionHashRow> {
    let mut current = hashes.iter().filter(|row| row.current);
    let row = current
        .next()
        .ok_or_else(|| anyhow::anyhow!("Execution intent {intent_id} has no current hash"))?;
    anyhow::ensure!(
        current.next().is_none(),
        "Execution intent {intent_id} has more than one current hash"
    );
    Ok(row)
}

/// Polls for the receipt of a broadcast transaction until it exists or the poll bound
/// is exhausted. A `null` receipt result is a legitimate pending response.
#[cfg(test)]
async fn poll_for_receipt(
    http_rpc_client: &BlockchainHttpRpcClient,
    tx_hash: &B256,
    max_polls: u32,
    interval: Duration,
) -> anyhow::Result<Option<RpcTransactionReceipt>> {
    let mut last_error = None;
    let mut observed_pending = false;

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Inspect the rows: SELECT id, transaction_hash, status, current FROM execution_transaction_hash WHERE intent_id = <id> ORDER BY id;
  2. If rows exist but none is current, set current = TRUE on the newest row matching the intent's on-chain reality (verify with eth_getTransactionByHash)
  3. If no rows exist and nothing was broadcast (intent stuck pre-broadcast), retire the intent (active = FALSE) so reconciliation proceeds
  4. Restore the 'one current hash per intent' invariant and prevent out-of-band edits to these tables

Example fix

-- before: all rows have current = FALSE
SELECT id, transaction_hash, current FROM execution_transaction_hash WHERE intent_id = 42;
-- (3 rows, all current = FALSE)

-- after: flag the newest verified row as current
UPDATE execution_transaction_hash
SET current = TRUE
WHERE id = (SELECT max(id) FROM execution_transaction_hash WHERE intent_id = 42);
Defensive patterns

Strategy: try-catch

Validate before calling

-- Invariant check before startup: every active intent past signing has exactly one current hash
SELECT i.id
FROM execution_intent i
JOIN execution_transaction_hash h ON h.intent_id = i.id
WHERE i.active AND i.status NOT IN ('prepared', 'signed')
GROUP BY i.id
HAVING count(*) FILTER (WHERE h.current) <> 1;
-- Zero rows expected; otherwise repair before connect().

Try / catch

try:
    client.connect()
except Exception as e:
    if 'has no current hash' in str(e):
        # inspect execution_transaction_hash for the intent, verify hashes on-chain,
        # flag the correct row current = TRUE (or deactivate a never-broadcast intent), then retry
        ...
    raise

Prevention

When it happens

Trigger: reconcile_unresolved_execution loading an intent whose execution_transaction_hash rows either are empty or all have current = FALSE: partial writes if the add_execution_transaction_hash commit was lost, manual row deletion, or external tools clearing flags.

Common situations: DB crash between intent activation and hash insert; DBAs trimming the hash-history table; a restored-from-backup database where later rows were lost.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/a9295e08391d8928. Report an issue: GitHub.