pandas-dev/pandas · error · ValueError
closed keyword does not match dtype.closed
Error message
closed keyword does not match dtype.closed
What it means
Raised in `_ensure_simple_new_inputs` when both an explicit `closed` keyword and an explicit `IntervalDtype` with a non-None `.closed` are passed, and they disagree (e.g. `closed='left'` with `dtype='interval[int64, right]'`). The closed attribute lives on the dtype, so pandas refuses a contradictory override.
Solutions
- Make closed consistent: specify it in only one place — either the keyword or the dtype.
- If the dtype came from an old pickle (closed is None), the keyword is used to fill it; do not pass a closed keyword when the dtype already carries one.
- Construct the dtype with matching closed: `IntervalDtype('int64', 'left')` together with `closed='left'`.
Example fix
# before
IntervalArray.from_arrays(l, r, closed='left', dtype=IntervalDtype('int64', 'right'))
# after - choose one source of truth
IntervalArray.from_arrays(l, r, closed='left')
# or
IntervalArray.from_arrays(l, r, dtype=IntervalDtype('int64', 'left')) Defensive patterns
Strategy: validation
Validate before calling
from pandas import IntervalDtype
def reconcile_closed(dtype, closed):
if isinstance(dtype, IntervalDtype) and dtype.closed is not None:
if closed is not None and closed != dtype.closed:
raise ValueError(f'closed={closed} conflicts with dtype.closed={dtype.closed}')
return dtype.closed
return closed Type guard
from pandas import IntervalDtype
def closed_is_consistent(dtype, closed) -> bool:
if isinstance(dtype, IntervalDtype) and dtype.closed is not None and closed is not None:
return dtype.closed == closed
return True Try / catch
try:
arr = IntervalArray.from_arrays(l, r, closed=closed, dtype=dtype)
except ValueError as e:
if 'closed keyword does not match' in str(e):
arr = IntervalArray.from_arrays(l, r, dtype=dtype) # let dtype win
else:
raise Prevention
- Specify closed in exactly one place (keyword OR dtype), never both with different values.
- When loading pickled IntervalDtype, do not also pass a closed keyword.
- Add a unit test asserting closed consistency when constructing from external config.
When it happens
Trigger: Passing `IntervalArray.from_arrays(left, right, closed='left', dtype=IntervalDtype('int64', 'right'))`; loading an old pickle whose dtype carries closed='right' while constructing with closed='left'.
Common situations: Building intervals interactively and toggling closed; serialised dtype carrying closed state recombined with a different keyword; refactoring where closed was moved into the dtype string.
Related errors
- Cannot modify read-only array
- invalid dtype
- left and right must have the same length
- left and right must have the same time zone, got
- left side of interval must be <= right side
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/04c547944298f1e2.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/interval.py:310
closed = closed or "right"
if dtype is not None:
# GH 19262: dtype must be an IntervalDtype to override inferred
dtype = pandas_dtype(dtype)
if isinstance(dtype, IntervalDtype):
if dtype.subtype is not None:
left = left.astype(dtype.subtype)
right = right.astype(dtype.subtype)
else:
msg = f"dtype must be an IntervalDtype, got {dtype}"
raise TypeError(msg)
if dtype.closed is None:
# possibly loading an old pickle
dtype = IntervalDtype(dtype.subtype, closed)
elif closed != dtype.closed:
raise ValueError("closed keyword does not match dtype.closed")
# coerce dtypes to match if needed
if is_float_dtype(left.dtype) and is_integer_dtype(right.dtype):
right = right.astype(left.dtype)
elif is_float_dtype(right.dtype) and is_integer_dtype(left.dtype):
left = left.astype(right.dtype)
if type(left) != type(right):
msg = (
f"must not have differing left [{type(left).__name__}] and "
f"right [{type(right).__name__}] types"
)
raise ValueError(msg)
if (
isinstance(left.dtype, CategoricalDtype)
or is_string_dtype(left.dtype)
or is_string_dtype(right.dtype)
):View on GitHub (pinned to 3b7651241d)