Repository: pandas-dev/pandas
File: pandas/core/groupby/groupby.py (Python)

Code before:
            # TODO: Better way to find # of observed groups?
            group_sizes = self._grouper.size()
            result_len = group_sizes[group_sizes > 0].shape[0]
            assert result_len <= expected_len
            has_unobserved = result_len < expected_len

            raise_err: bool | np.bool_ = not ignore_unobserved and has_unobserved
            # Only raise an error if there are columns to compute; otherwise we return
            # an empty DataFrame with an index (possibly including unobserved) but no
            # columns
            data = self._obj_with_exclusions
            if raise_err and isinstance(data, DataFrame):
                if numeric_only:
                    data = data._get_numeric_data()
                raise_err = len(data.columns) > 0

            if raise_err:
                raise ValueError(
                    f"Can't get {how} of an empty group due to unobserved categories. "
                    "Specify observed=True in groupby instead."
                )
        elif not skipna and self._obj_with_exclusions.isna().any(axis=None):
            raise ValueError(
                f"{type(self).__name__}.{how} with skipna=False encountered an NA "
                f"value."
            )

        result = self._agg_general(
            numeric_only=numeric_only,
            min_count=1,
            alias=how,
            skipna=skipna,
        )
        return result

    def _wrap_idxmax_idxmin(
        self, res: NDFrameT, how: Literal["idxmax", "idxmin"], skipna: bool
    ) -> NDFrameT:
        index = self.obj.index
        if res.size == 0:
            result = res.astype(index.dtype)
        elif skipna and res.lt(0).any(axis=None):
            raise ValueError(
                f"{type(self).__name__}.{how} with skipna=True encountered all NA "
                f"values in a group."
            )
        else:
            if isinstance(index, MultiIndex):
                index = index.to_flat_index()
            values = res._values
            assert isinstance(values, np.ndarray)

Review comment (suggestion):
Changing the error message here to not identify the type of object that is raising the error. This should be apparent to the user already. If we include the type, then we'll need to catch and rethrow in the DataFrame case with axis=1 and EAs.

Code after:
            # TODO: Better way to find # of observed groups?
            group_sizes = self._grouper.size()
            result_len = group_sizes[group_sizes > 0].shape[0]
            assert result_len <= expected_len
            has_unobserved = result_len < expected_len

            raise_err: bool | np.bool_ = not ignore_unobserved and has_unobserved
            # Only raise an error if there are columns to compute; otherwise we return
            # an empty DataFrame with an index (possibly including unobserved) but no
            # columns
            data = self._obj_with_exclusions
            if raise_err and isinstance(data, DataFrame):
                if numeric_only:
                    data = data._get_numeric_data()
                raise_err = len(data.columns) > 0

            if raise_err:
                raise ValueError(
                    f"Can't get {how} of an empty group due to unobserved categories. "
                    "Specify observed=True in groupby instead."
                )
        elif not skipna and self._obj_with_exclusions.isna().any(axis=None):
            raise ValueError(f"{how} with skipna=False encountered an NA value.")

        result = self._agg_general(
            numeric_only=numeric_only,
            min_count=1,
            alias=how,
            skipna=skipna,
        )
        return result

    def _wrap_idxmax_idxmin(
        self, res: NDFrameT, how: Literal["idxmax", "idxmin"], skipna: bool
    ) -> NDFrameT:
        index = self.obj.index
        if res.size == 0:
            result = res.astype(index.dtype)
        elif skipna and res.lt(0).any(axis=None):
            raise ValueError(
                f"{how} with skipna=True encountered all NA values in a group."
            )
        else:
            if isinstance(index, MultiIndex):
                index = index.to_flat_index()
            values = res._values
            assert isinstance(values, np.ndarray)
            na_value = na_value_for_dtype(index.dtype, compat=False)
            if isinstance(res, Series):
                # mypy: expression has type "Series", variable has type "NDFrameT"
                result = res._constructor(  # type: ignore[assignment]