nautechsystems/nautilus_trader · error · anyhow::Error

Stream pool events database error: {e}

Error message

Stream pool events database error: {e}

What it means

This error wraps the sqlx row-level error when the database stream yields an Err for a row fetch while streaming pool events. The library surfaces it so the consumer of the stream knows the failure came from the database read itself, not the transform logic.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:3270

                .bind(pos.transaction_index as i32)
                .bind(pos.log_index as i32)
                .bind(to_block.map(|block| block as i64))
                .fetch(&self.pool)
        } else {
            sqlx::query(QUERY_ALL)
                .bind(chain.chain_id as i32)
                .bind(pool_identifier.to_string())
                .bind(to_block.map(|block| block as i64))
                .fetch(&self.pool)
        };

        // Transform rows to events
        let stream = query.map(move |row_result| match row_result {
            Ok(row) => {
                transform_row_to_dex_pool_data(&row, chain.clone(), dex.clone(), instrument_id)
                    .map_err(|e| anyhow::anyhow!("Steam pool event transform error: {e}"))
            }
            Err(e) => Err(anyhow::anyhow!("Stream pool events database error: {e}")),
        });

        Box::pin(stream)
    }

    /// Persists an execution transaction record to the `execution_transaction` table.
    ///
    /// Records are written before broadcast so a signed transaction is never forgotten;
    /// the unique `(chain_id, transaction_hash)` constraint makes an exact re-insertion
    /// idempotent. Signer nonce ownership and order IDs are unique before broadcast. Order
    /// submission records carry the client order ID; operator transactions (wrap, approve)
    /// store `NULL`.
    ///
    /// # Errors
    ///
    /// Returns an error if the database operation fails.
    #[expect(
        clippy::too_many_arguments,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the inner `{e}` for the sqlx/sqlite/postgres error code
  2. Increase connection pool size or idle/checkout timeouts if pool exhaustion is the cause
  3. Add retry logic around stream consumption with resumable position (e.g. last log index)
  4. Verify network stability and Postgres max_connections settings

Example fix

// before
Err(e) => Err(anyhow::anyhow!("Stream pool events database error: {e}")),
// after
Err(e) => {
    tracing::error!(error = %e, "pool events stream db error");
    Err(anyhow::anyhow!("Stream pool events database error: {e}"))
}
Defensive patterns

Strategy: retry

Validate before calling

let healthy = sqlx::query("SELECT 1").execute(&pool).await.is_ok();
if !healthy { anyhow::bail!("database unavailable before streaming"); }

Try / catch

loop {
    match stream_events(...).await {
        Ok(stream) => { consume(stream).await; break; }
        Err(e) if is_transient(&e) => { backoff().await; continue; }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: Streaming pool events and the underlying connection drops mid-stream, a cursor/consumed-row error occurs, a statement timeout fires, or the connection is terminated by the server.

Common situations: Long-running streams over flaky networks; Postgres connection pool exhaustion or idle-connection timeout; server restarts during a live query.

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/4e37f6ea11fde3ff. Report an issue: GitHub.