pola-rs/polars · error · TypeError
expected type 'int | str', got {qualified_type_name(item)!r}
Error message
expected type 'int | str', got {qualified_type_name(item)!r} ({item!r}) What it means
Subscripting a struct expression (pl.col('s').struct[item]) dispatches on the item type in Python: str selects a field by name, int by zero-based index, and anything else raises a TypeError showing the qualified type and value. This happens before any Rust call; slices and expressions are not accepted subscripts.
Source
Thrown at py-polars/src/polars/expr/struct.py:75
>>> df.select(pl.col("s").struct[0])
shape: (2, 1)
┌─────┐
│ x │
│ --- │
│ i64 │
╞═════╡
│ 1 │
│ 2 │
└─────┘
"""
if isinstance(item, str):
return self.field(item)
elif isinstance(item, int):
return wrap_expr(self._pyexpr.struct_field_by_index(item))
else:
msg = f"expected type 'int | str', got {qualified_type_name(item)!r} ({item!r})"
raise TypeError(msg)
def field(self, name: str | list[str], *more_names: str) -> Expr:
"""
Retrieve one or multiple `Struct` field(s) as a new Series.
.. engine-support:: in-memory, streaming, distributed
Parameters
----------
name
Name of the struct field to retrieve.
*more_names
Additional struct field names.
Examples
--------
>>> df = pl.DataFrame(
... {View on GitHub (pinned to df599052da)
Solutions
- Select by name: .struct['field_name']
- Or use a plain int index, coercing foreign scalars: .struct[int(idx)]
- For multiple fields use .struct.field(['a', 'b'])
- Sanitize numpy scalars at the boundary: int(x) once, where the data enters your code
Example fix
# before
idx = int(np.argmax(counts))
pl.col('s').struct[np.argmax(counts)]
# after
pl.col('s').struct[int(idx)]
# or, more robustly, by name:
pl.col('s').struct['field_name'] Defensive patterns
Strategy: type-guard
Validate before calling
item = int(item) if isinstance(item, (int, float)) else item
if not isinstance(item, (str, int)):
raise TypeError(f'bad struct subscript: {item!r}')
expr = pl.col('s').struct[item] Type guard
import operator
def is_struct_key(x: object) -> bool:
return isinstance(x, str) or (isinstance(x, int) and not isinstance(x, bool))
# also coerce numpy integers at the boundary:
def coerce_struct_key(x: object) -> str | int:
if hasattr(x, 'item') and not isinstance(x, (str, bytes)):
x = operator.index(x) # numpy integers support __index__
return x # type: ignore[return-value] Prevention
- Coerce numpy scalars to Python int where they enter your code
- Prefer field names over indices for readability and resilience to schema changes
- Never pass slices or floats to .struct[...]
When it happens
Trigger: .struct[np.int64(0)] or .struct[0.0] (index computed via numpy or float division — np.int64 is not a Python int); .struct[None]; .struct[1:3] (slice); .struct[pl.col('f')].
Common situations: Indices produced by numpy operations (argmax, where) or read from JSON as floats; dynamic field selection code that sometimes yields None; users expecting slice semantics like pandas.
Related errors
- only 1D NumPy arrays can be treated as indices
- cannot treat NumPy array of type {arr.dtype} as indices
- "extract_groups" expects a `str`, given a {qualified_type_na
- mapping item must be a datatype or datatype expression; foun
- cannot select columns using key of type {qualified_type_name
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/a77dd8c95be97b30.
Report an issue: GitHub.