pandas-dev/pandas · error · ValueError

invalid option for 'closed

Error message

invalid option for 'closed': {closed}

What it means

Raised by IntervalArray.set_closed when 'closed' is not one of VALID_CLOSED = {'left', 'right', 'both', 'neither'}. The closed attribute must be a recognized value.

Solutions

  1. Use one of: 'left', 'right', 'both', 'neither'.
  2. Normalize input strings (e.g., .lower()) and validate against the allowed set before calling.
  3. Default closed from the source data instead of accepting arbitrary user input.

Example fix

// before
arr.set_closed('Both')
// after
arr.set_closed('both')
Defensive patterns

Strategy: validation

Validate before calling

VALID_CLOSED = {'left', 'right', 'both', 'neither'}

def safe_set_closed(arr, closed):
    if closed not in VALID_CLOSED:
        raise ValueError(f'closed must be one of {VALID_CLOSED}')
    return arr.set_closed(closed)

Type guard

def is_valid_closed(c):
    return c in {'left', 'right', 'both', 'neither'}

Prevention

When it happens

Trigger: arr.set_closed('both-sided'); arr.set_closed(None); arr.set_closed('Right') (case/typo); config-driven closed strings.

Common situations: Typos; user-derived config strings; case sensitivity; locale issues.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/1e0439088381c5ff. Report an issue: GitHub.

Appendix: source

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

        --------
        IntervalArray.closed : Returns inclusive side of the Interval.
        arrays.IntervalArray.closed : Returns inclusive side of the IntervalArray.

        Examples
        --------
        >>> index = pd.arrays.IntervalArray.from_breaks(range(4))
        >>> index
        <IntervalArray>
        [(0, 1], (1, 2], (2, 3]]
        Length: 3, dtype: interval[int64, right]
        >>> index.set_closed("both")
        <IntervalArray>
        [[0, 1], [1, 2], [2, 3]]
        Length: 3, dtype: interval[int64, both]
        """
        if closed not in VALID_CLOSED:
            msg = f"invalid option for 'closed': {closed}"
            raise ValueError(msg)

        left, right = self._left, self._right
        dtype = IntervalDtype(left.dtype, closed=closed)
        return self._simple_new(left, right, dtype=dtype)

    @property
    def is_non_overlapping_monotonic(self) -> bool:
        """
        Return a boolean whether the IntervalArray/IntervalIndex\
        is non-overlapping and monotonic.

        Non-overlapping means (no Intervals share points), and monotonic means
        either monotonic increasing or monotonic decreasing.

        See Also
        --------
        overlaps : Check if two IntervalIndex objects overlap.

View on GitHub (pinned to 3b7651241d)