pandas-dev/pandas · error · ValueError

left side of interval must be <= right side

Error message

left side of interval must be <= right side

What it means

Raised by `_validate` when any element has `left > right`. By definition an interval's lower bound must not exceed its upper bound (equality is allowed). Fires at pandas/core/arrays/interval.py:623.

Source

Thrown at pandas/core/arrays/interval.py:623

        * left is always below right
        """
        if not isinstance(dtype, IntervalDtype):
            msg = f"invalid dtype: {dtype}"
            raise ValueError(msg)
        if len(left) != len(right):
            msg = "left and right must have the same length"
            raise ValueError(msg)
        left_mask = notna(left)
        right_mask = notna(right)
        if not (left_mask == right_mask).all():
            msg = (
                "missing values must be missing in the same "
                "location both left and right sides"
            )
            raise ValueError(msg)
        if not (left[left_mask] <= right[left_mask]).all():
            msg = "left side of interval must be <= right side"
            raise ValueError(msg)

    def _shallow_copy(self, left, right) -> Self:
        """
        Return a new IntervalArray with the replacement attributes

        Parameters
        ----------
        left : Index
            Values to be used for the left-side of the intervals.
        right : Index
            Values to be used for the right-side of the intervals.
        """
        dtype = IntervalDtype(left.dtype, closed=self.closed)
        left, right, dtype = self._ensure_simple_new_inputs(left, right, dtype=dtype)

        return self._simple_new(left, right, dtype=dtype)

    # ---------------------------------------------------------------------

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Swap misordered bounds: `lo, hi = np.minimum(left, right), np.maximum(left, right)`.
  2. Drop invalid rows: `valid = left <= right; left, right = left[valid], right[valid]`.
  3. Verify column mapping in the source query/ETL.

Example fix

// before
pd.IntervalIndex.from_arrays(df['hi'], df['lo'])  # swapped
// after
import numpy as np
lo = np.minimum(df['hi'], df['lo'])
hi = np.maximum(df['hi'], df['lo'])
pd.IntervalIndex.from_arrays(lo, hi)
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def enforce_order(left, right):
    left = np.asarray(left)
    right = np.asarray(right)
    lo = np.minimum(left, right)
    hi = np.maximum(left, right)
    return lo, hi

Type guard

import numpy as np

def all_left_leq_right(left, right) -> bool:
    mask = ~(np.isnan(left) | np.isnan(right))
    return bool((left[mask] <= right[mask]).all())

Try / catch

try:
    ia = pd.IntervalArray(left, right)
except ValueError as e:
    if "left side of interval must be <= right side" in str(e):
        lo, hi = np.minimum(left, right), np.maximum(left, right)
        ia = pd.IntervalArray(lo, hi)
    else:
        raise

Prevention

When it happens

Trigger: `from_arrays([2, 1], [1, 2])`, swapped columns, or bounds computed from min/max where the source data is dirty.

Common situations: Column order accidentally swapped in a pipeline; high/low labels inverted; timezone or unit conversions that reverse ordering.

Related errors


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