pandas-dev/pandas · error · NotImplementedError

Default 'empty' implementation is invalid for dtype='{dtype}

Error message

Default 'empty' implementation is invalid for dtype='{dtype}'

What it means

Raised by BaseMaskedArray._empty when, after constructing an array filled with dtype._internal_fill_value and an all-True mask, the resulting object either is not an instance of cls or its dtype does not match the requested dtype. This indicates the masked-array subclass has misconfigured its class identity, its dtype property, or its _internal_fill_value, making the default empty() implementation invalid for that dtype.

Source

Thrown at pandas/core/arrays/masked.py:205

        return result

    @classmethod
    def _empty(cls, shape: Shape, dtype: ExtensionDtype) -> Self:
        """
        Create an ExtensionArray with the given shape and dtype.

        See also
        --------
        ExtensionDtype.empty
            ExtensionDtype.empty is the 'official' public version of this API.
        """
        dtype = cast("BaseMaskedDtype", dtype)
        values: np.ndarray = np.empty(shape, dtype=dtype.type)
        values.fill(dtype._internal_fill_value)
        mask = np.ones(shape, dtype=bool)
        result = cls(values, mask)
        if not isinstance(result, cls) or dtype != result.dtype:
            raise NotImplementedError(
                f"Default 'empty' implementation is invalid for dtype='{dtype}'"
            )
        return result

    def _formatter(self, boxed: bool = False) -> Callable[[Any], str | None]:
        # NEP 51: https://github.com/numpy/numpy/pull/22449
        return str

    @property
    def dtype(self) -> BaseMaskedDtype:
        raise AbstractMethodError(self)

    @overload
    def __getitem__(self, item: ScalarIndexer) -> Any: ...

    @overload
    def __getitem__(self, item: SequenceIndexer) -> Self: ...

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Override _empty (or ExtensionDtype.empty) in the subclass to return a correctly-typed instance.
  2. Verify dtype.type and dtype._internal_fill_value produce a value compatible with the subclass constructor.
  3. Ensure cls(values, mask) returns an instance whose .dtype equals the requested dtype.

Example fix

# before
class MyDtype(BaseMaskedDtype):
    type = np.float64
    _internal_fill_value = 0  # mismatched

# after
class MyArray(BaseMaskedArray):
    @classmethod
    def _empty(cls, shape, dtype):
        values = np.empty(shape, dtype=dtype.type)
        values.fill(dtype._internal_fill_value)
        return cls(values, np.ones(shape, dtype=bool))
Defensive patterns

Strategy: validation

Validate before calling

def empty_works(dtype, shape):
    arr = dtype.empty(shape)
    return isinstance(arr, type(arr)) and arr.dtype == dtype

Type guard

def subclass_consistent(cls, dtype) -> bool:
    try:
        a = cls._empty((1,), dtype)
        return isinstance(a, cls) and a.dtype == dtype
    except Exception:
        return False

Prevention

When it happens

Trigger: Authoring a custom ExtensionDtype/ExtensionArray subclass of BaseMaskedArray where dtype.type, _internal_fill_value, or the constructor don't line up; calling ExtensionDtype.empty(shape) on such a dtype.

Common situations: Library authors extending pandas masked arrays; mis-set class attributes after a refactor or dtype rename.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/3f2dc4d8855ff9e5. Report an issue: GitHub.