nautechsystems/nautilus_trader · error · anyhow::Error
Failed to get table last block for {table_name}: {e}
Error message
Failed to get table last block for {table_name}: {e} What it means
Wraps a sqlx error from a dynamically built SELECT that reads the last block stored in a specific per-event-family table (table_name interpolated into the query and guarded by AssertSqlSafe). Failure aborts determining where that family's stored events end.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:1694
///
/// # Errors
///
/// Returns an error if the database query fails.
pub async fn get_table_last_block(
&self,
chain_id: u32,
table_name: &str,
pool_identifier: &PoolIdentifier,
) -> anyhow::Result<Option<u64>> {
let query = format!(
"SELECT MAX(block) FROM {table_name} WHERE chain_id = $1 AND pool_identifier = $2"
);
let result = sqlx::query_as::<_, (Option<i64>,)>(AssertSqlSafe(query))
.bind(chain_id as i32)
.bind(pool_identifier.as_ref())
.fetch_optional(&self.pool)
.await
.map_err(|e| anyhow::anyhow!("Failed to get table last block for {table_name}: {e}"))?;
Ok(result.and_then(|(block_number,)| block_number.map(|b| b as u64)))
}
/// Adds a batch of pool fee collect events to the database using batch operations.
///
/// # Errors
///
/// Returns an error if the database operation fails.
pub async fn add_pool_collects_batch(
&self,
chain_id: u32,
collects: &[PoolFeeCollect],
) -> anyhow::Result<()> {
if collects.is_empty() {
return Ok(());
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the event-family table exists (migrations or table creation for the family) before querying
- Verify the table_name string matches the actual Postgres table (case/qualifier)
- Check connectivity and retry the idempotent read
- Inspect the wrapped sqlx error — `relation ... does not exist` points to a missing table
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the event-family table exists before querying it
if !KNOWN_EVENT_FAMILIES.contains(&table_name) {
return Err(anyhow::anyhow!("unknown event family table: {table_name}"));
}
sqlx::query(&format!("SELECT 1 FROM {table_name} LIMIT 1")).fetch_optional(&pool).await?; Try / catch
match get_table_last_block(table_name, chain_id, pool_id).await {
Ok(b) => b.unwrap_or(0),
Err(e) if e.to_string().contains("does not exist") => 0, // empty family table
Err(e) => return Err(e),
} Prevention
- Whitelist table names against known event families before interpolation
- Create family tables lazily before first query
- Migrate schema for every supported event family
When it happens
Trigger: Calling `get_table_last_block(table_name, chain_id, pool_identifier)` when the per-family table does not exist (AssertSqlSafe passes the name through but the server errors on a missing relation), the connection fails, or the query is cancelled.
Common situations: Event-family table not yet created by migrations; passing a table_name that does not match a real table; DB restart or timeout during event backfill.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- Failed to get dex last synced block: {e}
- Failed to get pool last synced block: {e}
- Failed to get pool event sync state: {e}
- Failed to get pool event-family checkpoints: {e}
- Failed to validate finalized header ledger: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/7cfca296442a60bd.
Report an issue: GitHub.