pandas-dev/pandas · error · ValueError

cannot assign mismatch length to masked array

Error message

cannot assign mismatch length to masked array

What it means

Raised by putmask_without_repeat (putmask.py:97) as a ValueError when a list-like `new` value is being applied through a boolean mask but its length matches neither the number of True positions in the mask nor the full length of the values array (nor 1). numpy's np.putmask would silently repeat/truncate, producing wrong results; pandas detects the length mismatch and refuses.

Source

Thrown at pandas/core/array_algos/putmask.py:97

    # TODO: this prob needs some better checking for 2D cases
    nlocs = mask.sum()
    if nlocs > 0 and is_list_like(new) and getattr(new, "ndim", 1) == 1:
        shape = np.shape(new)
        # np.shape compat for if setitem_datetimelike_compat
        #  changed arraylike to list e.g. test_where_dt64_2d
        if nlocs == shape[-1]:
            # GH#30567
            # If length of ``new`` is less than the length of ``values``,
            # `np.putmask` would first repeat the ``new`` array and then
            # assign the masked values hence produces incorrect result.
            # `np.place` on the other hand uses the ``new`` values at it is
            # to place in the masked locations of ``values``
            np.place(values, mask, new)
            # i.e. values[mask] = new
        elif mask.shape[-1] == shape[-1] or shape[-1] == 1:
            np.putmask(values, mask, new)
        else:
            raise ValueError("cannot assign mismatch length to masked array")
    else:
        np.putmask(values, mask, new)


def validate_putmask(
    values: ArrayLike | MultiIndex, mask: np.ndarray
) -> tuple[npt.NDArray[np.bool_], bool]:
    """
    Validate mask and check if this putmask operation is a no-op.
    """
    mask = extract_bool_array(mask)
    if mask.shape != values.shape:
        raise ValueError("putmask: mask and data must be the same size")

    noop = not mask.any()
    return mask, noop

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Size `other` to match either the full array length or exactly the number of True positions in the mask.
  2. Pass a scalar instead of a list for a constant replacement: df.where(cond, other=0).
  3. Use df.mask(cond, other) with a same-shaped Series whose index aligns, so pandas can align positions correctly.

Example fix

// before
s = pd.Series([1,2,3,4])
s.where([True,False,True,False], other=[99, 88])  # length 2 mismatches
// after
s.where([True,False,True,False], other=[99, 88, 99, 88])  # full length
// or
s.where([True,False,True,False], other=99)  # scalar
Defensive patterns

Strategy: validation

Validate before calling

nlocs = int(np.asarray(mask).sum())
new_len = len(new) if hasattr(new, '__len__') else 1
if new_len not in (1, nlocs, len(values)):
    raise ValueError(f'other has length {new_len}; expected 1, {nlocs}, or {len(values)}')

Type guard

def putmask_other_compatible(values, mask, other) -> bool:
    import numpy as np
    nlocs = int(np.asarray(mask).sum())
    if not hasattr(other, '__len__'):
        return True
    return len(other) in (1, nlocs, len(values))

Try / catch

try:
    df.where(cond, other=other)
except ValueError as e:
    if 'mismatch length' in str(e):
        df.where(cond, other=0)  # scalar fallback
    else:
        raise

Prevention

When it happens

Trigger: df.where(cond, other=[1,2,3]) or s.mask(cond, other) where len(other) is neither len(values), mask.sum(), nor 1. Hit at putmask.py:80-97 when nlocs > 0, new is 1-D, and nlocs != shape[-1] AND mask.shape[-1] != shape[-1] AND shape[-1] != 1.

Common situations: Passing a replacement list sized to a filtered subset rather than the full array; mismatched lengths after a reindex or filter; building `other` from value_counts().index or similar shape-changing ops; using a Series whose index doesn't align with the masked frame.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/980abcdc6acb0b73. Report an issue: GitHub.