{"record":{"id":"2acfc0ae6e77c508","repo":"pandas-dev/pandas","slug":"default-empty-implementation-is-invalid-for-dtyp","errorCode":null,"errorMessage":"Default 'empty' implementation is invalid for dtype='{dtype}'","messagePattern":"Default 'empty' implementation is invalid for dtype='(.+?)'","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/base.py","lineNumber":2862,"sourceCode":"    @classmethod\n    def _empty(cls, shape: Shape, dtype: ExtensionDtype):\n        \"\"\"\n        Create an ExtensionArray with the given shape and dtype.\n\n        See also\n        --------\n        ExtensionDtype.empty\n            ExtensionDtype.empty is the 'official' public version of this API.\n        \"\"\"\n        # Implementer note: while ExtensionDtype.empty is the public way to\n        # call this method, it is still required to implement this `_empty`\n        # method as well (it is called internally in pandas)\n        obj = cls._from_sequence([], dtype=dtype)\n\n        taker = np.broadcast_to(np.intp(-1), shape)\n        result = obj.take(taker, allow_fill=True)\n        if not isinstance(result, cls) or dtype != result.dtype:\n            raise NotImplementedError(\n                f\"Default 'empty' implementation is invalid for dtype='{dtype}'\"\n            )\n        return result\n\n    def _quantile(self, qs: npt.NDArray[np.float64], interpolation: str) -> Self:\n        \"\"\"\n        Compute the quantiles of self for each quantile in `qs`.\n\n        Parameters\n        ----------\n        qs : np.ndarray[float64]\n        interpolation: str\n\n        Returns\n        -------\n        same type as self\n        \"\"\"\n        mask = np.asarray(self.isna())","sourceCodeStart":2844,"sourceCodeEnd":2880,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/base.py#L2844-L2880","documentation":"_empty is the internal counterpart of ExtensionDtype.empty used to build an all-NA array of a given shape. The base default first builds an empty sequence via cls._from_sequence([], dtype=dtype), then takes indices broadcast to -1 (the all-NA placeholder) with allow_fill=True. If the resulting object is not an instance of cls or its dtype does not match, the default is deemed invalid and NotImplementedError is raised. This catches subclasses whose take/_from_sequence do not honor the NA contract.","triggerScenarios":"pandas internally requests an empty/NA-filled EA of a given shape (during reindex, alignment, or construction of a placeholder block) for a custom dtype whose _from_sequence([])/take does not reproduce the same dtype or return the same class. The validation in the base default then fails.","commonSituations":"A custom EA whose _from_sequence changes the dtype (e.g. upcasts), or whose take(allow_fill=True) returns a different wrapper class. A dtype whose na_value handling in take is inconsistent. Triggered indirectly through reindex/merge on frames containing the custom column.","solutions":["Override _empty on the subclass to construct the all-NA array directly without relying on the take-based default.","Ensure _from_sequence([], dtype=...) returns an instance of cls with exactly that dtype, and take([-1,...], allow_fill=True, fill_value=na_value) returns cls with the same dtype.","Verify self.dtype.na_value round-trips through take; align na_value in the ExtensionDtype."],"exampleFix":"// before\n# pandas internal reindex -> NotImplementedError: Default 'empty' implementation is invalid...\n\n// after\n@classmethod\ndef _empty(cls, shape, dtype):\n    import numpy as np\n    na = dtype.na_value\n    data = np.broadcast_to(na, shape)\n    return cls._from_sequence(data, dtype=dtype)","handlingStrategy":"validation","validationCode":"# Verify _from_sequence/take round-trip the dtype before pandas calls _empty\nimport numpy as np\nempty = type(arr)._from_sequence([], dtype=arr.dtype)\ntaker = np.intp(-1)\nresult = empty.take(np.array([taker]), allow_fill=True)\nassert isinstance(result, type(arr)) and result.dtype == arr.dtype","typeGuard":null,"tryCatchPattern":"try:\n    out = dtype.empty((5,))\nexcept NotImplementedError:\n    # subclass does not honor the default; build NA-filled manually\n    import numpy as np\n    out = type(arr)._from_sequence(np.full(5, dtype.na_value), dtype=dtype)","preventionTips":["Ensure _from_sequence([], dtype=...) returns an instance of cls with exactly that dtype.","Ensure take(allow_fill=True) preserves class and dtype.","Override _empty if the take-based default does not fit your storage layout."],"tags":["extension-array","not-implemented","dtype","missing-data","pandas"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}