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 by IntervalArray construction when both the `closed` keyword ('left'|'right'|'both'|'neither') and an IntervalDtype carrying its own `.closed` attribute are supplied, and the two disagree. The library treats `closed` as a single source of truth, so an explicit conflict is a programming error rather than something to silently pick. It fires in pandas/core/arrays/interval.py:310 inside `_ensure_simple_new_inputs`.
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 71959b8cb9)
Solutions
- Pass `closed` in only one place: either via the IntervalDtype or via the `closed` keyword, not both.
- If you must reuse a dtype, normalize it first: `IntervalDtype(dtype.subtype, closed='right')` and drop the `closed=` keyword.
- When loading old pickles, reconstruct the IntervalArray without the stale dtype and let pandas infer `closed`.
Example fix
// before
pd.IntervalArray(left, right, closed='right', dtype=pd.IntervalDtype('int64', closed='left'))
// after
pd.IntervalArray(left, right, closed='right')
// or
pd.IntervalArray(left, right, dtype=pd.IntervalDtype('int64', closed='right')) Defensive patterns
Strategy: validation
Validate before calling
def safe_interval_array(left, right, *, closed=None, dtype=None):
if closed is not None and dtype is not None:
d = pd.core.dtypes.dtypes.IntervalDtype.__class__
from pandas import IntervalDtype
if isinstance(dtype, IntervalDtype) and dtype.closed is not None and dtype.closed != closed:
raise ValueError(f"closed={closed!r} conflicts with dtype.closed={dtype.closed!r}")
return pd.IntervalArray(left, right, closed=closed, dtype=dtype) Type guard
from pandas import IntervalDtype
def closed_consistent(dtype, closed) -> bool:
return not isinstance(dtype, IntervalDtype) or dtype.closed is None or closed is None or dtype.closed == closed Try / catch
try:
ia = pd.IntervalArray(left, right, closed=closed, dtype=dtype)
except ValueError as e:
if "closed keyword does not match" in str(e):
ia = pd.IntervalArray(left, right, closed=closed) # drop dtype.closed
else:
raise Prevention
- Pass `closed` from exactly one source (keyword OR IntervalDtype).
- When copying a dtype from another object, rebuild it via IntervalDtype(subtype, closed).
- Unit-test construction paths with both `closed` and `dtype` arguments.
When it happens
Trigger: Calling `pd.IntervalArray(..., closed='right', dtype=pd.IntervalDtype(..., closed='left'))`, or `pd.IntervalIndex.from_arrays(left, right, closed='both', dtype='interval[left]')`, or restoring an old pickle whose IntervalDtype already stores `closed` while the constructor call also passes an explicit `closed`.
Common situations: Migrating code that previously inferred closed-ness, passing a dtype string like 'interval[int64, left]' alongside `closed='right'`, or copying a dtype from another object whose `.closed` differs from the desired one.
Related errors
- must not have differing left [{type(left).__name__}] and rig
- category, object, and string subtypes are not supported for
- Period dtypes are not supported, use a PeriodIndex instead
- Left and right arrays must have matching signedness. Got {le
- invalid dtype: {dtype}
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/04c547944298f1e2.
Report an issue: GitHub.