sqlalchemy/sqlalchemy · error · ValueError

Operands must be the same length

Error message

Operands must be the same length

What it means

Raised by BitString.__and__ (the bitwise `&` operator) at lib/sqlalchemy/dialects/postgresql/bitstring.py:264-265 when the two operands differ in bit length. Bitwise AND is only defined element-wise, so mismatched lengths are rejected rather than zero-padded. Non-str operands return NotImplemented instead (letting Python try the reflected operator).

Source

Thrown at lib/sqlalchemy/dialects/postgresql/bitstring.py:265

            ~BitString("01010") == BitString("10101")
        """
        return BitString("".join("1" if x == "0" else "0" for x in self))

    def __and__(self, o: str) -> BitString:
        """Performs a bitwise and (``&``) with the given operand.
        A ``ValueError`` is raised if the operand is not the same length.

        e.g.::

            BitString("011") & BitString("011") == BitString("010")
        """

        if not isinstance(o, str):
            return NotImplemented
        o = BitString(o)
        if len(self) != len(o):
            raise ValueError("Operands must be the same length")

        return BitString(
            "".join(
                "1" if (x == "1" and y == "1") else "0"
                for x, y in zip(self, o)
            ),
            False,
        )

    def __or__(self, o: str) -> BitString:
        """Performs a bitwise or (``|``) with the given operand.
        A ``ValueError`` is raised if the operand is not the same length.

        e.g.::

            BitString("011") | BitString("010") == BitString("011")
        """
        if not isinstance(o, str):

View on GitHub (pinned to d9b44cb731)

Solutions

  1. Normalize both operands to the same length first, e.g. with zfill(width) or lstrip('0') on both.
  2. Build masks from the same BitString source/width as the data: mask = BitString.from_int(0b1010, len(data)).
  3. Validate len(a) == len(b) before the operation and log the mismatch for diagnosis.

Example fix

// before
result = value & BitString('1010')  # value is 8 bits
// after
result = value & BitString('1010').zfill(len(value))
Defensive patterns

Strategy: validation

Validate before calling

other_bs = BitString(other) if not isinstance(other, BitString) else other
if len(bs) != len(other_bs):
    raise ValueError('Operands must be the same length for &')
result = bs & other_bs

Type guard

def same_length(a: BitString, b) -> bool:
    return isinstance(b, str) and len(a) == len(BitString(b))

Try / catch

try:
    result = bs & other
except ValueError as e:
    if 'same length' in str(e):
        # pad the shorter operand on the left with zeros
        n = max(len(bs), len(BitString(other)))
        result = bs.zfill(n) & BitString(other).zfill(n)

Prevention

When it happens

Trigger: BitString('011') & BitString('0110'), or any `&` where len(left) != len(right). Common after lstrip/strip/from_int produce strings of differing width.

Common situations: Combining a BIT(8) column value with a hand-built mask of different width; operands sourced from columns resized at different times; one side came from from_int(length=4) and the other from raw bytes (length=8).

Related errors


AI-assisted analysis of sqlalchemy/sqlalchemy@d9b44cb731 (2026-08-01). Data as JSON: /data/errors/cec09d7dce74cb25.json. Report an issue: GitHub.