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

  1. Read the underlying `{e}` to see whether the failure is SQL-level or row-mapping level.
  2. Remove or repair rows with unparseable decimals/symbol values from the `token` table.
  3. Run migrations so the queried columns exist for the deployed schema.
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/c665398e5afb5d79. Report an issue: GitHub.