{"record":{"id":"bad698bdb5b6c206","repo":"transact-rs/sqlx","slug":"pgbinditer-is-only-used-once","errorCode":null,"errorMessage":"PgBindIter is only used once","messagePattern":"PgBindIter is only used once","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sqlx-postgres/src/bind_iter.rs","lineNumber":140,"sourceCode":"        if iter.next().is_some() {\n            let iter_size = std::cmp::max(lower_size_hint, OVERFLOW);\n            return Err(format!(\"encoded iterator is too large for Postgres: {iter_size}\").into());\n        }\n\n        // set the length now that we know what it is.\n        buf[len_start..(len_start + 4)].copy_from_slice(&count.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'q, I> Encode<'q, Postgres> for PgBindIter<I>\nwhere\n    I: Iterator,\n    <I as Iterator>::Item: Type<Postgres> + Encode<'q, Postgres>,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        Self::encode_inner(self.0.take().expect(\"PgBindIter is only used once\"), buf)\n    }\n    fn encode(self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError>\n    where\n        Self: Sized,\n    {\n        Self::encode_inner(\n            self.0.into_inner().expect(\"PgBindIter is only used once\"),\n            buf,\n        )\n    }\n}\n","sourceCodeStart":122,"sourceCodeEnd":152,"githubUrl":"https://github.com/transact-rs/sqlx/blob/03af8bcc5711a1935580a54bea249c219a0c217d/sqlx-postgres/src/bind_iter.rs#L122-L152","documentation":"`PgBindIter` wraps an iterator for one-time binding as a SQL parameter, backed by an `Option`/`Take`-like inner field. Because encoding consumes the iterator, encoding the same value twice is invalid; the library panics via `.expect(\"PgBindIter is only used once\")` in `encode_by_ref` when the inner value was already taken. This guards against silently re-using a half-consumed iterator, which would encode wrong data.","triggerScenarios":"Encoding a `PgBindIter` value by reference more than once — e.g. passing the same `&PgBindIter` to two query executions, or a driver code path that calls `encode_by_ref` twice on the same argument (such as in prepared-statement re-execution or retry logic that re-encodes arguments).","commonSituations":"Re-running a query in a loop with the same bound value; caching an encoded argument and re-encoding; sqlx internal paths that encode arguments once at prepare time and again at execute time.","solutions":["Create a fresh `PgBindIter` (from a new/cloned iterator or factory closure) for each query execution","If the source collection is reusable, wrap a `Vec`/slice rather than a one-shot iterator, or clone the underlying collection per execution","Avoid passing the same PgBindIter by reference into multiple `.bind()` calls","If retrying queries, rebuild all bound arguments inside the retry loop"],"exampleFix":"// before\nlet iter = PgBindIter::new(rows.into_iter());\nlet q1 = query!().bind(&iter); // ok\nlet q2 = query!().bind(&iter); // panics: only used once\n// after\nlet q1 = query!().bind(PgBindIter::new(rows.iter().cloned()));\nlet q2 = query!().bind(PgBindIter::new(rows.iter().cloned()));","handlingStrategy":"validation","validationCode":"fn fresh_bind<'q, I>(src: &[I::Item]) -> PgBindIter<std::vec::IntoIter<I::Item>>\nwhere I: Iterator, I::Item: Clone {\n    PgBindIter::new(src.to_vec().into_iter())\n}","typeGuard":null,"tryCatchPattern":"std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| value.encode_by_ref(&mut buf)))\n    .unwrap_or_else(|_| panic!(\"PgBindIter already consumed; create a new one\"));","preventionTips":["Treat PgBindIter as single-use: never store it in structs that outlive one query","Rebuild bound arguments inside retry loops","Prefer binding collections (Vec/slice) when the data must be reused","If you must reuse, keep a source collection and clone-into a new PgBindIter each bind"],"tags":["rust","sqlx","postgres","iterator","panic"],"backgroundTag":"iterator-consumed-twice","analyzedSha":"03af8bcc5711a1935580a54bea249c219a0c217d","analyzedAt":"2026-09-03T15:01:28.752Z","contentChangedAt":"2026-09-03T15:01:28.752Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}