{"record":{"id":"ed771a5ee2839f77","repo":"nautechsystems/nautilus_trader","slug":"stale-quote-pool-state-at-block-profiler-block","errorCode":null,"errorMessage":"Stale quote: pool state at block {profiler_block}, latest block {latest_block}, exceeds `max_quote_age_blocks` {max_age_blocks}","messagePattern":"Stale quote: pool state at block (.+?), latest block (.+?), exceeds `max_quote_age_blocks` (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":4275,"sourceCode":"        pool.dex.flash_created_event.as_deref(),\n        pool.dex.fee_protocol_update_event.as_deref(),\n        pool.dex.fee_protocol_collect_event.as_deref(),\n    ]\n    .into_iter()\n    .flatten()\n}\n\nfn validate_quote_age(\n    profiler_block: u64,\n    latest_block: u64,\n    max_age_blocks: u64,\n) -> anyhow::Result<()> {\n    anyhow::ensure!(\n        profiler_block <= latest_block,\n        \"Pool state at block {profiler_block} is ahead of the latest block {latest_block}; the execution RPC endpoint lags the data feed\"\n    );\n    let quote_age = latest_block - profiler_block;\n    anyhow::ensure!(\n        quote_age <= max_age_blocks,\n        \"Stale quote: pool state at block {profiler_block}, latest block {latest_block}, exceeds `max_quote_age_blocks` {max_age_blocks}\"\n    );\n    Ok(())\n}\n\nfn validate_rpc_transaction_matches_payload(\n    transaction: &RpcTransaction,\n    raw_transaction: &[u8],\n) -> anyhow::Result<()> {\n    let signed = decode_signed_transaction(raw_transaction)?;\n    anyhow::ensure!(\n        transaction.hash == signed.hash\n            && transaction.from == signed.signer\n            && transaction.nonce == signed.nonce\n            && transaction.chain_id == Some(signed.chain_id)\n            && transaction.transaction_type == Some(2)\n            && transaction.to == Some(signed.to)","sourceCodeStart":4257,"sourceCodeEnd":4293,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L4257-L4293","documentation":"validate_quote_age also enforces that the quote's age, computed as latest_block - profiler_block, does not exceed max_age_blocks. This error means the pool state backing the quote is older than the configured staleness budget, so the quote is considered too stale to execute against and is rejected.","triggerScenarios":"Calling validate_quote_age where (latest_block - profiler_block) > max_age_blocks — i.e., the pool state snapshot used for the quote is many blocks behind the execution endpoint's latest block.","commonSituations":"max_quote_age_blocks configured too tightly for feed latency; slow pool-state refresh loop; data feed outage/backfill leaving stale cache; bursty block times making a normally-acceptable age exceed the limit.","solutions":["Re-fetch pool state at the latest block and rebuild the quote before executing.","Increase max_quote_age_blocks to a realistic bound for your feed latency, if the current value is stricter than your SLA requires.","Reduce pool-state refresh interval or add a feed-health alert so stale snapshots are not reused.","Check the data feed for outages/gaps causing stale cached pool state."],"exampleFix":"// before: stale cached quote reused\nlet quote = cached_pool_quote(pool);\nvalidate_quote_age(quote.block, latest_block, cfg.max_quote_age_blocks)?;\n\n// after: refresh when stale\nif latest_block - cached_pool_quote(pool).block > cfg.max_quote_age_blocks {\n    refresh_pool_quote(&mut cache, pool, latest_block).await?;\n}\nlet quote = cached_pool_quote(pool);\nvalidate_quote_age(quote.block, latest_block, cfg.max_quote_age_blocks)?;","handlingStrategy":"validation","validationCode":"let latest_block = exec_rpc.get_block_number().await?;\nif latest_block.saturating_sub(quote_block) > cfg.max_quote_age_blocks {\n    refresh_pool_quote(pool, latest_block).await?;\n}","typeGuard":null,"tryCatchPattern":"match client.get_pool_quote(pool).await {\n    Ok(q) => q,\n    Err(e) if e.to_string().contains(\"Stale quote\") => {\n        refresh_pool_quote(pool, latest_block).await?;\n        client.get_pool_quote(pool).await\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Set max_quote_age_blocks based on measured feed latency","Refresh pool state on a schedule tighter than the staleness budget","Alert on data-feed gaps that leave stale cached quotes"],"tags":["staleness","quote","blockchain","configuration"],"backgroundTag":"invalid-config-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}