nautechsystems/nautilus_trader · error · anyhow::Error
Execution intent {} has unknown purpose {}
Error message
Execution intent {} has unknown purpose {} What it means
During startup reconciliation, TransactionPurpose::parse() returned None for the intent's persisted purpose column. The parser only accepts the exact strings "wrap", "approve", and "swap" (WETH deposit, ERC-20 approve, Uniswap V3 exactInputSingle). Any other value means the row cannot be mapped to a known replay strategy, so reconciliation aborts.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:934
return Ok(());
};
anyhow::ensure!(
intent.schema_version == crate::execution::transaction::EXECUTION_SCHEMA_VERSION,
"Execution intent {} uses unsupported schema version {}",
intent.id,
intent.schema_version
);
if matches!(intent.status.as_str(), "prepared" | "signed") {
database
.mark_execution_intent_recoverable(intent.id)
.await?;
release_preparing_slot(&self.in_flight);
return Ok(());
}
let purpose = TransactionPurpose::parse(&intent.purpose).ok_or_else(|| {
anyhow::anyhow!(
"Execution intent {} has unknown purpose {}",
intent.id,
intent.purpose
)
})?;
let nonce = intent
.nonce
.ok_or_else(|| anyhow::anyhow!("Active execution intent {} has no nonce", intent.id))?;
let hashes = database.get_execution_transaction_hashes(intent.id).await?;
let current = current_execution_hash(intent.id, &hashes)?;
let tx_hash = B256::from_str(¤t.transaction_hash).with_context(|| {
format!(
"Execution intent {} has invalid transaction hash {}",
intent.id, current.transaction_hash
)
})?;
*self.in_flight.lock().expect("in-flight mutex poisoned") =
Some(InFlightSlot::AwaitingFinality(InFlightTransaction {View on GitHub (pinned to 2114cf6f76)
Solutions
- Inspect the row: SELECT id, purpose, status FROM execution_intent WHERE active AND purpose NOT IN ('wrap','approve','swap');
- If the intent is genuinely one of the known purposes, correct the string (lowercase, no whitespace)
- If it was written by a newer version, reconcile with that version or archive the row (set active = FALSE) after confirming no funds are at risk
- Restrict write access to the execution tables so only the NautilusTrader process mutates them
Example fix
-- before SELECT id, purpose FROM execution_intent WHERE active; -- purpose = 'Swap ' (trailing space, parse fails) -- after UPDATE execution_intent SET purpose = 'swap' WHERE id = 42;
Defensive patterns
Strategy: validation
Validate before calling
-- Verify persisted purposes are parseable before startup
SELECT id, purpose
FROM execution_intent
WHERE active
AND purpose NOT IN ('wrap', 'approve', 'swap');
-- Expect zero rows before calling connect(). Type guard
def is_known_purpose(value: str) -> bool:
return value in ('wrap', 'approve', 'swap') Try / catch
try:
client.connect()
except Exception as e:
if 'unknown purpose' in str(e):
# inspect/repair execution_intent.purpose, then retry connect
...
raise Prevention
- Never hand-edit purpose strings in the execution_intent table; if you must, keep to lowercase wrap/approve/swap
- Reconcile pending intents with the same binary version that created them before switching versions
When it happens
Trigger: An active execution_intent row whose purpose is not exactly 'wrap', 'approve', or 'swap': manually edited rows, a newer binary that persisted an additional purpose enum variant, or data written into the table by another tool.
Common situations: Hand-fixing rows in Postgres during incident response; running a newer adapter version against a store read by an older one; typos introduced by ETL jobs touching the execution_intent table.
Related errors
- Active execution intent {} has no nonce
- Execution intent {intent_id} has no current hash
- Execution intent {intent_id} has more than one current hash
- Execution transaction hash {transaction_hash} was not found
- Replacement hash {transaction_hash} conflicts with another i
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/ca6b3a33baa03402.
Report an issue: GitHub.