{"record":{"id":"32d9f5ed4ebd86ec","repo":"pandas-dev/pandas","slug":"dtype-must-be-an-intervaldtype-got-dtype","errorCode":null,"errorMessage":"dtype must be an IntervalDtype, got {dtype}","messagePattern":"dtype must be an IntervalDtype, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/interval.py","lineNumber":304,"sourceCode":"        left = ensure_index(left, copy=copy)\n\n        right = ensure_index(right, copy=copy)\n\n        if closed is None and isinstance(dtype, IntervalDtype):\n            closed = dtype.closed\n\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            )","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/interval.py#L286-L322","documentation":"Raised by IntervalArray._ensure_simple_new_inputs (via _simple_new validation) when a dtype is supplied but, after pandas_dtype resolution, it is not an IntervalDtype. Interval arrays require an IntervalDtype subtype; any other dtype (int64, float64, category, etc.) is rejected. TypeError echoing the bad dtype.","triggerScenarios":"pd.arrays.IntervalArray(data, dtype='int64'); pd.IntervalIndex(..., dtype='float64'); passing a numeric or extension dtype that is not an IntervalDtype.","commonSituations":"Confusing the subtype (the inner numeric dtype) with the array dtype; passing the underlying bound dtype instead of 'interval[...]'.","solutions":["Use an IntervalDtype, e.g. dtype='interval[int64]' or dtype=pd.IntervalDtype('int64').","Omit dtype and let pandas infer it from the interval data.","To change the bound precision, set the subtype inside the IntervalDtype string, not as a bare dtype."],"exampleFix":"# before\npd.IntervalIndex.from_breaks([0, 1, 2], dtype='int64')\n# after\npd.IntervalIndex.from_breaks([0, 1, 2], dtype='interval[int64]')","handlingStrategy":"validation","validationCode":"def validate_interval_dtype(dtype):\n    if dtype is not None and not isinstance(pd.api.pandas_dtype(dtype), pd.IntervalDtype):\n        raise TypeError(f'dtype must be IntervalDtype, got {dtype!r}')\n    return dtype","typeGuard":"def is_interval_dtype(dtype) -> bool:\n    return isinstance(pd.api.pandas_dtype(dtype), pd.IntervalDtype) if dtype is not None else False","tryCatchPattern":null,"preventionTips":["Use 'interval[subtype]' strings for interval arrays.","Don't pass the inner bound dtype as the array dtype.","Let pandas infer dtype when unsure."],"tags":["interval","dtype","construction","pandas"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}