transact-rs/sqlx · error · io::Error (InvalidData)

VARBIT data contains other characters than 1 or 0.

Error message

VARBIT data contains other characters than 1 or 0.

What it means

sqlx's BitVec decoding for Postgres parses the VARBIT/BIT text representation as a string of '0' and '1' characters. When the server sends text-format data containing any other character, the decoder cannot map it to bits and fails with this io::ErrorKind::InvalidData error. It indicates corrupted or unexpected wire data rather than a caller mistake in most cases.

Source

Thrown at sqlx-postgres/src/types/bit_vec.rs:87

                // 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()?;
                let mut bit_vec = BitVec::with_capacity(s.len());

                for c in s.chars() {
                    match c {
                        '0' => bit_vec.push(false),
                        '1' => bit_vec.push(true),
                        _ => {
                            Err(io::Error::new(
                                io::ErrorKind::InvalidData,
                                "VARBIT data contains other characters than 1 or 0.",
                            ))?;
                        }
                    }
                }

                Ok(bit_vec)
            }
        }
    }
}

View on GitHub (pinned to 03af8bcc57)

Solutions

  1. Use the binary protocol so BIT/VARBIT values are sent as raw bytes: keep default prepared statements, or cast explicitly to a text-safe type in SQL
  2. Check the actual column data with `SELECT col::text` for stray characters (prefixes, spaces) and clean the data
  3. Decode to String or Vec<u8> instead of BitVec if the column may hold non-canonical bit text, and parse it yourself
  4. Verify the column type is actually BIT/VARBIT, not TEXT that merely looks like bits

Example fix

// before: decoding a possibly hex-prefixed column directly into BitVec
let bits: bitvec::vec::BitVec = sqlx::query_scalar("SELECT flags FROM t").fetch_one(&pool).await?;
// after: normalize in SQL or decode as text and parse
let raw: String = sqlx::query_scalar("SELECT flags::text FROM t").fetch_one(&pool).await?;
let cleaned: String = raw.chars().filter(|c| *c == '0' || *c == '1').collect();
Defensive patterns

Strategy: validation

Validate before calling

// validate text-form bit data before decoding into BitVec
fn is_valid_bit_text(s: &str) -> bool {
    !s.is_empty() && s.chars().all(|c| c == '0' || c == '1')
}
let raw: String = sqlx::query_scalar("SELECT flags::text FROM t").fetch_one(&pool).await?;
assert!(is_valid_bit_text(&raw), "unexpected BIT text: {raw:?}");

Type guard

fn as_bit_text(v: &str) -> Option<Vec<bool>> {
    v.chars().map(|c| match c { '0' => Some(false), '1' => Some(true), _ => None }).collect()
}

Try / catch

match result {
    Ok(bits) => handle(bits),
    Err(e) if e.to_string().contains("VARBIT data contains other characters") => {
        // fall back to parsing raw text yourself
        let raw: String = sqlx::query_scalar("SELECT flags::text FROM t").fetch_one(&pool).await?;
        handle(parse_bits_manually(&raw)?);
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Decoding a Postgres BIT or VARBIT column into sqlx's BitVec when the value arrives in PgValueFormat::Text and contains characters other than 0/1, e.g. binary-format-like escapes, a prefixed 'B'/'X' literal, or whitespace.

Common situations: Querying a bit column through a proxy or driver setting that forces text protocol; manually cast values like `bit 'X1F'` or hex/bit strings stored with prefixes; reading a column whose declared type differs from stored data after a migration.

Related errors


AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03). Data as JSON: /api/errors/7cfc8101e1ac19ac. Report an issue: GitHub.