…le complex dtype metadata
pd.read_parquet() (and Table.to_pandas() generally) raises TypeError when
a column's pandas metadata records a complex ArrowDtype (list, struct,
dictionary, ...) as its 'numpy_type', e.g.
"list<item: string>[pyarrow]". _get_extension_dtypes() passes this string
straight to pandas.api.types.pandas_dtype(), which cannot parse nested
Arrow type syntax and raises TypeError -- so any DataFrame that has such
a column can never round-trip through parquet with the default (numpy)
backend, and this has stayed broken since 2023.
apacheGH-39914 previously fixed the case where an explicit types_mapper /
dtype_backend="pyarrow" is passed, by resolving those columns earlier so
this code path is skipped entirely. The default backend, and any
metadata-only path with no types_mapper, still hit the crash.
Fix: when pandas_dtype(dtype) raises TypeError, fall back to building the
ArrowDtype directly from the schema's actual field type instead of
giving up. The schema always has the precise type available regardless
of whether the metadata string can be parsed back.
Verified against pandas 3.0.4 + pyarrow 24.0.0: list, struct, and
dictionary ArrowDtype columns now round-trip through to_pandas() and
parquet with no types_mapper/dtype_backend needed, a double
write/read/write/read round-trip of a struct column still works, and
plain numpy dtypes plus simple extension dtypes (Int64) are unaffected.
Fixes pandas-dev/pandas#53011
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rationale for this change
pd.read_parquet()(andTable.to_pandas()generally, with notypes_mapper/dtype_backend="pyarrow") raisesTypeErrorfor anycolumn whose pandas metadata records a complex
ArrowDtype-- list,struct, or dictionary -- as its
numpy_type, e.g."list<item: string>[pyarrow]". This has been broken since the metadataround-tripping was introduced, and is the long-standing root cause of
pandas-dev/pandas#53011 (open since 2023, still reproducing today with
no workaround at the pandas level).
#39914 (this PR's linked issue) previously fixed the case where an
explicit
types_mapper/dtype_backend="pyarrow"is passed at readtime -- #44720 resolved those columns earlier in
_get_extension_dtypes,so the buggy string-parsing branch is skipped entirely for that path.
The default backend, and any metadata-only path with no
types_mapper, still hit the original crash -- which is why the pandasissue has stayed open and users keep re-discovering it (see the thread's
comments through 2025-08).
What changes are included in this PR?
In
_get_extension_dtypes(), whenpandas_dtype(dtype)raisesTypeErroron the metadata'snumpy_typestring, fall back to buildingthe
ArrowDtypedirectly from the schema's actual field type(
table.schema.field(name).type) instead of propagating the error. Theschema always carries the precise type regardless of whether the
metadata string happens to be parseable, and this is exactly the pattern
several commenters on the pandas issue independently proposed (e.g.
this comment)
but that was never implemented in a merged fix.
Are these changes tested?
Added
test_to_pandas_extension_dtypes_mapping_complex_type_no_types_mapper,covering both a list and a struct
ArrowDtypecolumn round-trippedthrough
Table.to_pandas()with notypes_mapper-- the exact casethat previously crashed. Confirmed red on unpatched code / green after
the fix.
Also manually verified (not just the new test) against pandas 3.0.4 +
pyarrow 24.0.0:
ArrowDtypecolumns round-trip throughboth the default backend and
dtype_backend="pyarrow".scenario from this comment)
still works.
Int64) areunaffected -- no regression to the already-working paths.
Are there any user-facing changes?
This PR contains a "Critical Fix".
This makes
pd.read_parquet(...)(default backend, nodtype_backend="pyarrow"needed) work for any DataFrame containing acomplex
ArrowDtypecolumn (list/struct/dictionary), which currentlyraises an opaque
TypeErrorand has no workaround short of stripping thepandas metadata before writing.
AI Generation Disclosure
I used Claude Code (an AI coding assistant) for this PR. It found the bug by searching for confirmed, still-open, high-severity issues across large open-source projects; root-caused it by tracing
pandas_compat.pyagainst the linked pandas issue and the earlier partial fix (#44720); wrote the fallback in_get_extension_dtypes()and the new test; drafted this description; and ran the red/green check and the manual round-trip checks above against a fresh install of pandas 3.0.4 + pyarrow 24.0.0. I'm happy to make any changes and to answer questions about it myself.