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
- Inspect the wrapped sqlx::Error for transport vs server-abort cause
- Run copy_pools first so FK parents exist
- Diff write_pool_liquidity_update_binary's writes against the COPY column list post-migration
- 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
- Run copy_pools before liquidity updates (FK ordering)
- Verify tick field serialization (i32 big-endian, fixed width) after migrations
- Chunk updates for isolated retries
- Watch DB logs for early session aborts
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
- Failed to write block data: {e}
- Failed to write pool swap data: {e}
- Failed to write COPY header: {e}
- Failed to load active execution intent: {e}
- Failed to start replacement transaction persistence: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/be9ede3cbaf57a5a.
Report an issue: GitHub.