nautechsystems/nautilus_trader · error · anyhow::Error
Failed to load tokens: {e}
Error message
Failed to load tokens: {e} What it means
Wraps failures while fetching and mapping all valid token rows for a chain into `Token` domain objects. Both the SQL fetch and the per-row conversion can fail; whichever errors is surfaced through this message. Invalid tokens (rows with error info) are deliberately excluded from the result.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:1318
pub async fn load_tokens(&self, chain: SharedChain) -> anyhow::Result<Vec<Token>> {
sqlx::query_as::<_, TokenRow>("SELECT * FROM token WHERE chain_id = $1 AND error IS NULL")
.bind(chain.chain_id as i32)
.fetch_all(&self.pool)
.await
.map(|rows| {
rows.into_iter()
.map(|token_row| {
Token::new(
chain.clone(),
token_row.address,
token_row.name,
token_row.symbol,
token_row.decimals,
)
})
.collect::<Vec<_>>()
})
.map_err(|e| anyhow::anyhow!("Failed to load tokens: {e}"))
}
/// Retrieves all invalid token addresses for a given chain.
///
/// # Errors
///
/// Returns an error if the database query fails or address validation fails.
pub async fn load_invalid_token_addresses(
&self,
chain_id: u32,
) -> anyhow::Result<Vec<Address>> {
sqlx::query_as::<_, (String,)>(
"SELECT address FROM token WHERE chain_id = $1 AND error IS NOT NULL",
)
.bind(chain_id as i32)
.fetch_all(&self.pool)
.await?
.into_iter()View on GitHub (pinned to 18893faf8b)
Solutions
- Read the underlying `{e}` to see whether the failure is SQL-level or row-mapping level.
- Remove or repair rows with unparseable decimals/symbol values from the `token` table.
- Run migrations so the queried columns exist for the deployed schema.
- Confirm the database is reachable and the pool is healthy before bulk loads.
Example fix
// before: any bad row aborts the whole load
.map_err(|e| anyhow::anyhow!("Failed to load tokens: {e}"))
// after: repair the offending row data instead
// UPDATE token SET decimals = 18 WHERE chain_id = 1 AND decimals IS NULL; Defensive patterns
Strategy: validation
Validate before calling
// sanity-check stored token rows before bulk loading
let bad: (i64,) = sqlx::query_as(
"SELECT count(*) FROM token WHERE chain_id = $1 AND (decimals IS NULL OR decimals < 0 OR symbol IS NULL)",
).bind(chain_id).fetch_one(&pool).await?;
if bad.0 > 0 { log::warn!("{bad} token rows will fail domain conversion"); } Try / catch
let tokens = match self.load_tokens(chain).await {
Ok(t) => t,
Err(e) if e.to_string().contains("decimals") => {
log::error!("corrupt token row: {e}; repair token table before retry");
Vec::new()
}
Err(e) => return Err(e),
}; Prevention
- Validate token decimals/symbol at write time so bad rows never enter the table.
- Run migrations before app startup cache loads.
- Schedule a periodic data-integrity query on the token table.
- Keep an eye on fetch_all size; paginate very large token sets.
When it happens
Trigger: Calling the token-loading method (database.rs, load tokens for chain) when the SELECT fails (connection, missing table/column) or when row-to-Token conversion fails, e.g. a stored symbol/decimals row that cannot be parsed into the domain type.
Common situations: Querying a chain_id with a corrupted token row (bad decimals value) that fails domain validation; running the app against an older DB schema lacking a column; pool connection dropped during fetch_all.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- Failed to load pools: {e}
- Failed to load pool {pool_identifier}: {e}
- Failed to seed chain table: {e}
- Failed to call create_block_partition for chain {}: {e}
- Failed to call create_token_partition for chain {}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c665398e5afb5d79.
Report an issue: GitHub.