transact-rs/sqlx · error · io::Error (InvalidData)
VARBIT length mismatch.
Error message
VARBIT length mismatch.
What it means
Postgres VARBIT/BIT values are decoded by reading the declared bit length and computing the expected byte count (`len.div_ceil(8)`). If the wire buffer's remaining bytes don't exactly match that count, the payload is malformed, and decoding fails with `InvalidData` and 'VARBIT length mismatch.'.
Source
Thrown at sqlx-postgres/src/types/bit_vec.rs:61
fn size_hint(&self) -> usize {
mem::size_of::<i32>() + self.len()
}
}
impl Decode<'_, Postgres> for BitVec {
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
match value.format() {
PgValueFormat::Binary => {
let mut bytes = value.as_bytes()?;
let len = bytes.get_i32();
let len = usize::try_from(len).map_err(|_| format!("invalid VARBIT len: {len}"))?;
// The smallest amount of data we can read is one byte
let bytes_len = len.div_ceil(8);
if bytes.remaining() != bytes_len {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"VARBIT length mismatch.",
))?;
}
let mut bitvec = BitVec::from_bytes(bytes);
// Chop off zeroes from the back. We get bits in bytes, so if
// our bitvec is not in full bytes, extra zeroes are added to
// the end.
while bitvec.len() > len {
bitvec.pop();
}
Ok(bitvec)
}
PgValueFormat::Text => {
let s = value.as_str()?;View on GitHub (pinned to 03af8bcc57)
Solutions
- Verify the column type and data with psql (`SELECT bit_length(col), col FROM ...`) to confirm server-side integrity
- Re-insert or recompute the affected BIT/VARBIT values if data is corrupted
- Remove/fix any proxy or custom protocol layer mangling the BIT payload
- If you control encoding, ensure the payload is exactly `ceil(len/8)` bytes for the declared bit length
Example fix
// before: fixture with mismatched declared length vs bytes let value: BitVec = sqlx::decode::decode(&[0u8, 9, 0xFF].encode()[..])?; // len=9 but 1 byte only? mismatch cases panic here // after: encode with matching length prefix let bits = BitVec::from_slice(&[0b1111_1111, 0b1000_0000]); let encoded = PgBitVec::encode(bits); // consistent len/bytes
Defensive patterns
Strategy: try-catch
Validate before calling
// sanity-check length consistency before decoding raw bytes let len = u32::from_be_bytes(raw[0..4].try_into().unwrap()) as usize; assert_eq!(raw.len() - 4, len.div_ceil(8), "BIT payload length mismatch");
Try / catch
match row.try_get::<BitVec, _>("flags") {
Ok(bits) => bits,
Err(e) if e.to_string().contains("VARBIT length mismatch") => {
// log and inspect raw column data; treat row as corrupt
BitVec::new()
}
Err(e) => return Err(e.into()),
} Prevention
- Write BIT/VARBIT values only through sqlx or psql, not hand-rolled wire frames
- Avoid intermediaries/proxies that rewrite result payloads
- Validate affected columns after schema migrations or data imports
- Add a round-trip encode/decode test for BIT columns in your test suite
When it happens
Trigger: Decoding a BIT/VARBIT column whose received payload length disagrees with its declared bit length — corrupted/truncated result data, or a custom/proxy server emitting a non-conforming wire format.
Common situations: Bit column written by another tool with an inconsistent length prefix; values produced through an intermediate server or driver with a wire-format bug; manually hand-crafted test fixtures with wrong byte counts.
Related errors
- failed to parse DATABASE_URL
- PgBindIter is only used once
- unimplemented!()
- expected to read {} bytes, got {} bytes at EOF
- Hostname did not resolve to any addresses
AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03).
Data as JSON: /api/errors/46b1fd849a5cf62c.
Report an issue: GitHub.