pandas-dev/pandas · error · AttributeError

Can only use the '.struct' accessor with 'struct[pyarrow]' d

Error message

Can only use the '.struct' accessor with 'struct[pyarrow]' dtype, not {dtype}.

What it means

The .struct accessor requires dtype struct[pyarrow]. Line 52 raises AttributeError when the dtype IS an ArrowDtype but the underlying pyarrow type is not a struct (e.g. int64[pyarrow], string[pyarrow], list[pyarrow]). AttributeError is used so hasattr/inspect treat the accessor as absent on non-struct columns.

Source

Thrown at pandas/core/arrays/arrow/accessors.py:52

    @abstractmethod
    def __init__(self, data, validation_msg: str) -> None:
        self._data = data
        self._validation_msg = validation_msg
        self._validate(data)

    @abstractmethod
    def _is_valid_pyarrow_dtype(self, pyarrow_dtype) -> bool:
        pass

    def _validate(self, data) -> None:
        dtype = data.dtype
        if not HAS_PYARROW or not isinstance(dtype, ArrowDtype):
            # Raise AttributeError so that inspect can handle non-struct Series.
            raise AttributeError(self._validation_msg.format(dtype=dtype))

        if not self._is_valid_pyarrow_dtype(dtype.pyarrow_dtype):
            # Raise AttributeError so that inspect can handle invalid Series.
            raise AttributeError(self._validation_msg.format(dtype=dtype))

    @property
    def _pa_array(self):
        return self._data.array._pa_array


class ListAccessor(ArrowAccessor):
    """
    Accessor object for list data properties of the Series values.

    Parameters
    ----------
    data : Series
        Series containing Arrow list data.
    """

    def __init__(self, data=None) -> None:
        super().__init__(

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Ensure the Series is built with a pa.struct([...]) dtype via pd.ArrowDtype.
  2. Reconstruct the column from dict/list data with the struct dtype before using .struct.

Example fix

// before
s.struct.field("a")  # s.dtype == string[pyarrow]
// after
import pyarrow as pa
s = pd.Series([...], dtype=pd.ArrowDtype(pa.struct([("a", pa.string())])))
s.struct.field("a")
Defensive patterns

Strategy: type-guard

Validate before calling

def to_struct_pa(s, fields):
    import pyarrow as pa
    from pandas.core.dtypes.dtypes import ArrowDtype
    if not (isinstance(s.dtype, ArrowDtype) and pa.types.is_struct(s.dtype.pyarrow_dtype)):
        s = pd.Series(list(s), dtype=ArrowDtype(pa.struct(fields)))
    return s

Type guard

def is_struct_pyarrow(s) -> bool:
    import pyarrow as pa
    from pandas.core.dtypes.dtypes import ArrowDtype
    d = s.dtype
    return isinstance(d, ArrowDtype) and pa.types.is_struct(d.pyarrow_dtype)

Prevention

When it happens

Trigger: s.struct.field('x') (or s.struct.dtypes) on a Series whose dtype is a non-struct pyarrow type such as int64[pyarrow], string[pyarrow], or list[pyarrow].

Common situations: Assuming a column is struct when it is a primitive pyarrow type; schema drift after data ingestion.

Related errors


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