nautechsystems/nautilus_trader · error · anyhow::Error

Failed to write pool liquidity update data: {e}

Error message

Failed to write pool liquidity update data: {e}

What it means

write_pool_liquidity_update_binary serializes one PoolLiquidityUpdate (including tick_lower/tick_upper i32 fields) and sends it over the COPY BINARY stream; a send failure is wrapped in this message. The whole copy_pool_liquidity_updates batch aborts via `?`. As with other row writers, the cause is a dead connection or an already-aborted COPY session.

Source

Thrown at crates/adapters/blockchain/src/cache/copy.rs:618

        row_data.write_all(&(owner_bytes.len() as i32).to_be_bytes())?;
        row_data.write_all(&owner_bytes)?;

        write_copy_numeric(&mut row_data, update.position_liquidity);
        write_copy_numeric(&mut row_data, update.amount0);
        write_copy_numeric(&mut row_data, update.amount1);

        let tick_lower_bytes = update.tick_lower.to_be_bytes();
        row_data.write_all(&(tick_lower_bytes.len() as i32).to_be_bytes())?;
        row_data.write_all(&tick_lower_bytes)?;

        let tick_upper_bytes = update.tick_upper.to_be_bytes();
        row_data.write_all(&(tick_upper_bytes.len() as i32).to_be_bytes())?;
        row_data.write_all(&tick_upper_bytes)?;

        copy_in
            .send(row_data)
            .await
            .map_err(|e| anyhow::anyhow!("Failed to write pool liquidity update data: {e}"))?;
        Ok(())
    }

    /// Inserts pool fee collect events using PostgreSQL COPY BINARY for maximum performance.
    ///
    /// # Errors
    ///
    /// Returns an error if the COPY operation fails.
    pub async fn copy_pool_collects(
        &self,
        chain_id: u32,
        collects: &[PoolFeeCollect],
    ) -> anyhow::Result<()> {
        if collects.is_empty() {
            return Ok(());
        }

        let copy_statement = "

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the wrapped sqlx::Error for transport vs server-abort cause
  2. Run copy_pools first so FK parents exist
  3. Diff write_pool_liquidity_update_binary's writes against the COPY column list post-migration
  4. Retry in smaller chunks to isolate the bad row
Defensive patterns

Strategy: retry

Try / catch

match handler.copy_pool_liquidity_updates(chain_id, &updates).await {
    Err(e) if e.to_string().contains("Failed to write pool liquidity update data") => {
        tokio::time::sleep(Duration::from_secs(5)).await;
        handler.copy_pool_liquidity_updates(chain_id, &updates).await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Connection loss mid-stream, server abort of the COPY from a previously written bad row, or a serialization mismatch (field order/width) with the pool_liquidity_update column list after a schema change.

Common situations: Long backfills interrupted by network blips; liquidity updates written before their parent pools (earlier-row FK failure surfacing here); migrations altering the table while the writer is unchanged.

Related errors


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