pandas-dev/pandas · error · ValueError

invalid dtype

Error message

invalid dtype: {dtype}

What it means

Raised in `_validate` when the supplied dtype is not an IntervalDtype. `_validate` is the final structural check over left/right/dtype; the dtype must be a fully-formed IntervalDtype (not a subtype string and not None after construction).

Solutions

  1. Use the public constructors (`IntervalArray(...)`, `from_arrays`, `from_tuples`, `from_breaks`) which produce a valid IntervalDtype.
  2. If you must call `_validate`, build the dtype with `IntervalDtype(subtype, closed)` first.
  3. Avoid passing strings like 'int64'; pass `IntervalDtype('int64', 'right')`.

Example fix

# before (private misuse)
arr._validate(left, right, dtype='int64')

# after
arr._validate(left, right, dtype=IntervalDtype('int64', 'right'))
Defensive patterns

Strategy: type-guard

Validate before calling

from pandas import IntervalDtype

def ensure_interval_dtype(dtype):
    if not isinstance(dtype, IntervalDtype):
        raise ValueError(f'expected IntervalDtype, got {type(dtype)}')
    return dtype

Type guard

from pandas import IntervalDtype

def is_interval_dtype_obj(dtype) -> bool:
    return isinstance(dtype, IntervalDtype)

Try / catch

try:
    arr._validate(left, right, dtype)
except ValueError as e:
    if 'invalid dtype' in str(e):
        from pandas import IntervalDtype
        arr._validate(left, right, IntervalDtype(dtype))
    else:
        raise

Prevention

When it happens

Trigger: Internal/programmatic calls that bypass `_ensure_simple_new_inputs` and pass a raw numpy dtype or string to `_validate`; constructing via `_simple_new` with a wrong dtype; pickle/reconstruction edge cases.

Common situations: Subclassing IntervalArray and overriding construction; custom array wrappers that forward a dtype without converting; misuse of private API.

Related errors


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

Appendix: source

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

            right.append(rhs)

        return cls.from_arrays(left, right, closed, copy=False, dtype=dtype)

    @classmethod
    def _validate(cls, left, right, dtype: IntervalDtype) -> None:
        """
        Verify that the IntervalArray is valid.

        Checks that

        * dtype is correct
        * left and right match lengths
        * left and right have the same missing values
        * left is always below right
        """
        if not isinstance(dtype, IntervalDtype):
            msg = f"invalid dtype: {dtype}"
            raise ValueError(msg)
        if len(left) != len(right):
            msg = "left and right must have the same length"
            raise ValueError(msg)
        left_mask = notna(left)
        right_mask = notna(right)
        if not (left_mask == right_mask).all():
            msg = (
                "missing values must be missing in the same "
                "location both left and right sides"
            )
            raise ValueError(msg)
        if not (left[left_mask] <= right[left_mask]).all():
            msg = "left side of interval must be <= right side"
            raise ValueError(msg)

    def _shallow_copy(self, left, right) -> Self:
        """
        Return a new IntervalArray with the replacement attributes

View on GitHub (pinned to 3b7651241d)