{"record":{"id":"c86732f464ae3274","repo":"nautechsystems/nautilus_trader","slug":"failed-to-write-copy-trailer-e","errorCode":null,"errorMessage":"Failed to write COPY trailer: {e}","messagePattern":"Failed to write COPY trailer: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/copy.rs","lineNumber":918,"sourceCode":"            .send(row_data)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to write pool data: {e}\"))?;\n        Ok(())\n    }\n\n    /// Writes the PostgreSQL COPY binary format trailer.\n    ///\n    /// The trailer is a 2-byte value of -1 to indicate end of data.\n    async fn write_copy_trailer(\n        &self,\n        copy_in: &mut sqlx::postgres::PgCopyIn<sqlx::pool::PoolConnection<sqlx::Postgres>>,\n    ) -> anyhow::Result<()> {\n        // Binary trailer: -1 as i16 to indicate end of data\n        let trailer = (-1i16).to_be_bytes();\n        copy_in\n            .send(trailer.to_vec())\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to write COPY trailer: {e}\"))?;\n        Ok(())\n    }\n}\n\nfn write_copy_numeric(row: &mut Vec<u8>, value: impl Display) {\n    let value = value.to_string();\n    row.extend_from_slice(&(value.len() as i32).to_be_bytes());\n    row.extend_from_slice(value.as_bytes());\n}\n","sourceCodeStart":900,"sourceCodeEnd":928,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/copy.rs#L900-L928","documentation":"write_copy_trailer sends the 2-byte (-1 i16) binary COPY trailer that terminates every binary COPY stream. If the sink rejects the trailer, the COPY cannot be finalized and the server will discard the stream; this error wraps that send failure. It is shared by all copy_* functions (blocks, tokens, pools, swaps, liquidity updates, collects).","triggerScenarios":"copy_in.send(trailer) fails at the end of any copy_* operation — almost always because the connection or COPY stream already broke (rows earlier failed, connection dropped, server aborted), leaving no valid channel for the trailer.","commonSituations":"A mid-stream row error silently closed the sink so the trailer fails; idle timeout triggered between last row and trailer; database restarted during a large backfill.","solutions":["Investigate the earlier rows/errors first — the trailer failure is nearly always a secondary symptom","Check connection liveness and TCP keepalive settings for long COPY operations","Retry the full copy_* operation; partial COPY data is not committed when the trailer fails","Verify no intermediate layer (pool, pgbouncer) is terminating the session during COPY"],"exampleFix":"// before: treating trailer failure as root cause\nmatch write_copy_trailer(&mut copy_in).await {\n    Err(e) => log::error!(\"trailer failed: {e}\"), // hides real cause\n    ...\n}\n// after: surface the full error chain for diagnosis\nwrite_copy_trailer(&mut copy_in).await\n    .map_err(|e| e.context(\"COPY trailer failed; check prior row errors and connection health\"))?;","handlingStrategy":"try-catch","validationCode":"// health-check the connection before starting a COPY sequence\nsqlx::raw_sql(\"SELECT 1\").fetch_one(&pool).await?;","typeGuard":null,"tryCatchPattern":"async fn copy_with_trailer_guard<F, Fut>(op: F) -> anyhow::Result<()>\nwhere F: Fn() -> Fut, Fut: Future<Output = anyhow::Result<()>> {\n    op().await.map_err(|e|\n        // trailer failures are usually secondary; surface the full chain\n        anyhow::anyhow!(\"COPY sequence failed (check row errors/connection): {e:#}\")\n    )\n}","preventionTips":["Treat trailer errors as symptoms: always inspect earlier row errors in the same COPY","Configure TCP keepalive so idle gaps between rows don't drop the connection","Avoid PgBouncer transaction pooling modes that can interrupt COPY sessions","Retry the entire copy_* call — the server discards unterminated COPY data"],"tags":["database","postgres","copy","trailer"],"backgroundTag":"database-write-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}