pandas-dev/pandas · error · AttributeError
Can only use the '.struct' accessor with 'struct[pyarrow]'…
Error message
Can only use the '.struct' accessor with 'struct[pyarrow]' dtype, not {dtype}. What it means
`AttributeError` from `ArrowAccessor._validate` for the `.struct` accessor. It fires when the Series dtype is not an `ArrowDtype` over a pyarrow struct type (`pa.types.is_struct` returns False). Like the `.list` case it uses `AttributeError` so the accessor is hidden from non-struct Series (correct `hasattr` / tab-completion behavior).
Solutions
- Construct/convert with an explicit struct dtype: `s.astype(pd.ArrowDtype(pa.struct([(k, pa.int64()) for k in keys])))`.
- If loading from records, use `pd.array(records, dtype=pd.ArrowDtype(pa.struct(...)))`.
- Guard with `isinstance(s.dtype, pd.ArrowDtype) and pa.types.is_struct(s.dtype.pyarrow_dtype)`.
Example fix
// before
s = pd.Series([{'a':1},{'a':2}])
s.struct.field('a') # object dtype -> AttributeError
// after
import pyarrow as pa
s = pd.Series([{'a':1},{'a':2}], dtype=pd.ArrowDtype(pa.struct([('a', pa.int64())])))
s.struct.field('a') Defensive patterns
Strategy: type-guard
Validate before calling
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 = s.astype(pd.ArrowDtype(pa.struct([(k, pa.int64()) for k in keys])))
s.struct.field('a') Type guard
def is_arrow_struct_series(s) -> bool:
import pyarrow as pa
from pandas.core.dtypes.dtypes import ArrowDtype
return isinstance(s.dtype, ArrowDtype) and pa.types.is_struct(s.dtype.pyarrow_dtype) Try / catch
try:
out = s.struct.field('a')
except AttributeError as e:
if '.struct' in str(e):
s = s.astype(pd.ArrowDtype(pa.struct([('a', pa.int64')])))
out = s.struct.field('a')
else:
raise Prevention
- Cast dict-valued Series to ArrowDtype(pa.struct(...)) before using .struct
- Check dtype when loading parquet/JSON into struct Series
When it happens
Trigger: `s.struct.field('x')` / `s.struct.explode()` where `s.dtype` is object/dict-of-dict, an Arrow non-struct type (`string[pyarrow]`, `int64[pyarrow]`), or a non-Arrow dtype.
Common situations: Loading JSON/parquet into a Series of dicts and forgetting to cast to a struct Arrow dtype; field-access code that assumes pyarrow storage; dtype silently downcast.
Related errors
- Can only use the '.list' accessor with 'list[pyarrow]'…
- name_or_index must be an int, str, bytes…
- key must be an int or slice, got
- to_concat must have the same dtype
- ' ' object is not iterable
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/b1ec3e278611f03d.
Report an issue: GitHub.
Appendix: 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 3b7651241d)