{"record":{"id":"04c547944298f1e2","repo":"pandas-dev/pandas","slug":"closed-keyword-does-not-match-dtype-closed","errorCode":null,"errorMessage":"closed keyword does not match dtype.closed","messagePattern":"closed keyword does not match dtype\\.closed","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/interval.py","lineNumber":310,"sourceCode":"\n        closed = closed or \"right\"\n\n        if dtype is not None:\n            # GH 19262: dtype must be an IntervalDtype to override inferred\n            dtype = pandas_dtype(dtype)\n            if isinstance(dtype, IntervalDtype):\n                if dtype.subtype is not None:\n                    left = left.astype(dtype.subtype)\n                    right = right.astype(dtype.subtype)\n            else:\n                msg = f\"dtype must be an IntervalDtype, got {dtype}\"\n                raise TypeError(msg)\n\n            if dtype.closed is None:\n                # possibly loading an old pickle\n                dtype = IntervalDtype(dtype.subtype, closed)\n            elif closed != dtype.closed:\n                raise ValueError(\"closed keyword does not match dtype.closed\")\n\n        # coerce dtypes to match if needed\n        if is_float_dtype(left.dtype) and is_integer_dtype(right.dtype):\n            right = right.astype(left.dtype)\n        elif is_float_dtype(right.dtype) and is_integer_dtype(left.dtype):\n            left = left.astype(right.dtype)\n\n        if type(left) != type(right):\n            msg = (\n                f\"must not have differing left [{type(left).__name__}] and \"\n                f\"right [{type(right).__name__}] types\"\n            )\n            raise ValueError(msg)\n        if (\n            isinstance(left.dtype, CategoricalDtype)\n            or is_string_dtype(left.dtype)\n            or is_string_dtype(right.dtype)\n        ):","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/interval.py#L292-L328","documentation":"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`.","triggerScenarios":"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`.","commonSituations":"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.","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`."],"exampleFix":"// before\npd.IntervalArray(left, right, closed='right', dtype=pd.IntervalDtype('int64', closed='left'))\n// after\npd.IntervalArray(left, right, closed='right')\n// or\npd.IntervalArray(left, right, dtype=pd.IntervalDtype('int64', closed='right'))","handlingStrategy":"validation","validationCode":"def safe_interval_array(left, right, *, closed=None, dtype=None):\n    if closed is not None and dtype is not None:\n        d = pd.core.dtypes.dtypes.IntervalDtype.__class__\n        from pandas import IntervalDtype\n        if isinstance(dtype, IntervalDtype) and dtype.closed is not None and dtype.closed != closed:\n            raise ValueError(f\"closed={closed!r} conflicts with dtype.closed={dtype.closed!r}\")\n    return pd.IntervalArray(left, right, closed=closed, dtype=dtype)","typeGuard":"from pandas import IntervalDtype\n\ndef closed_consistent(dtype, closed) -> bool:\n    return not isinstance(dtype, IntervalDtype) or dtype.closed is None or closed is None or dtype.closed == closed","tryCatchPattern":"try:\n    ia = pd.IntervalArray(left, right, closed=closed, dtype=dtype)\nexcept ValueError as e:\n    if \"closed keyword does not match\" in str(e):\n        ia = pd.IntervalArray(left, right, closed=closed)  # drop dtype.closed\n    else:\n        raise","preventionTips":["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."],"tags":["interval","dtype","constructor","validation"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}