pandas-dev/pandas · error · ValueError

name_or_index must be an int, str, bytes, pyarrow.compute.Ex

Error message

name_or_index must be an int, str, bytes, pyarrow.compute.Expression, or list of those

What it means

Thrown by StructAccessor.field (pandas Series.struct.field) when the field selector is not one of the accepted types. The inner get_name helper validates the selector against int, str, bytes, a pyarrow.compute.Expression, or a list-like of those used to drill into nested structs. Anything else (e.g. a float, tuple, dict, None) hits the final else branch and raises. It is a strict input-validation guard before calling pc.struct_field.

Source

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

                name = level_name_or_index
            elif isinstance(level_name_or_index, pc.Expression):
                name = str(level_name_or_index)
            elif is_list_like(level_name_or_index):
                # For nested input like [2, 1, 2]
                # iteratively get the struct and field name. The last
                # one is used for the name of the index.
                level_name_or_index = list(reversed(level_name_or_index))
                selected = data
                while level_name_or_index:
                    # we need the cast, otherwise mypy complains about
                    # getting ints, bytes, or str here, which isn't possible.
                    level_name_or_index = cast("list", level_name_or_index)
                    name_or_index = level_name_or_index.pop()
                    name = get_name(name_or_index, selected)
                    selected = selected.type.field(selected.type.get_field_index(name))
                    name = selected.name
            else:
                raise ValueError(
                    "name_or_index must be an int, str, bytes, "
                    "pyarrow.compute.Expression, or list of those"
                )
            return name

        pa_arr = self._data.array._pa_array
        name = get_name(name_or_index, pa_arr)
        field_arr = pc.struct_field(pa_arr, name_or_index)

        return Series(
            field_arr,
            dtype=ArrowDtype(field_arr.type),
            index=self._data.index,
            name=name,
        )

    def explode(self) -> DataFrame:
        """

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Coerce numeric selectors to int before calling: s.struct.field(int(field_idx)).
  2. Pass the struct field name as a str: s.struct.field('my_field').
  3. For nested struct access, pass a list of int/str such as s.struct.field([0, 'child']).
  4. If building a pyarrow expression, pass pc.struct_field(...) style Expression objects directly.

Example fix

# before
idx = payload['field']  # may be 2.5 or None from JSON
s.struct.field(idx)
# after
idx = payload['field']
assert isinstance(idx, (int, str, bytes)), f'bad field selector {idx!r}'
s.struct.field(int(idx) if isinstance(idx, (int, float)) and float(idx).is_integer() else idx)
Defensive patterns

Strategy: validation

Validate before calling

import pyarrow.compute as pc

def valid_struct_field(x):
    return (
        isinstance(x, (int, str, bytes))
        or isinstance(x, pc.Expression)
        or (hasattr(x, '__iter__') and all(isinstance(i, (int, str, bytes, pc.Expression)) for i in x))
    )

# before: s.struct.field(selector)
assert valid_struct_field(selector), f'invalid field selector {selector!r}'
s.struct.field(selector)

Type guard

from typing import Union, List
import pyarrow.compute as pc

StructFieldSelector = Union[int, str, bytes, pc.Expression, List[Union[int, str, bytes, pc.Expression]]]

def is_struct_field_selector(x) -> bool:
    if isinstance(x, (int, str, bytes, pc.Expression)):
        return True
    if hasattr(x, '__iter__') and not isinstance(x, (str, bytes)):
        return all(isinstance(i, (int, str, bytes, pc.Expression)) for i in x)
    return False

Try / catch

try:
    col = s.struct.field(selector)
except ValueError as e:
    if 'name_or_index must be' in str(e):
        raise ValueError(f'Bad struct field selector {selector!r}; expected int/str/bytes/Expression/list') from e
    raise

Prevention

When it happens

Trigger: Calling `s.struct.field(<X>)` where <X> is not int/str/bytes/pyarrow Expression/list. Examples: `s.struct.field(2.5)`, `s.struct.field(None)`, `s.struct.field(('a','b'))` where tuple is rejected by is_list_like path, or passing a pyarrow Type object instead of a field name/index.

Common situations: Dynamically building the field selector from user input or config and passing a float index (e.g. JSON-parsed number), passing None as a 'no-op' field, or confusing the struct field name with a column expression object. Common when reading nested schemas and indexing by a value that came in as a non-int numeric.

Related errors


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