{"record":{"id":"b85a6bd6e44b84c6","repo":"pandas-dev/pandas","slug":"name-or-index-must-be-an-int-str-bytes-pyarrow","errorCode":null,"errorMessage":"name_or_index must be an int, str, bytes, pyarrow.compute.Expression, or list of those","messagePattern":"name_or_index must be an int, str, bytes, pyarrow\\.compute\\.Expression, or list of those","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/arrow/accessors.py","lineNumber":463,"sourceCode":"                name = level_name_or_index\n            elif isinstance(level_name_or_index, pc.Expression):\n                name = str(level_name_or_index)\n            elif is_list_like(level_name_or_index):\n                # For nested input like [2, 1, 2]\n                # iteratively get the struct and field name. The last\n                # one is used for the name of the index.\n                level_name_or_index = list(reversed(level_name_or_index))\n                selected = data\n                while level_name_or_index:\n                    # we need the cast, otherwise mypy complains about\n                    # getting ints, bytes, or str here, which isn't possible.\n                    level_name_or_index = cast(\"list\", level_name_or_index)\n                    name_or_index = level_name_or_index.pop()\n                    name = get_name(name_or_index, selected)\n                    selected = selected.type.field(selected.type.get_field_index(name))\n                    name = selected.name\n            else:\n                raise ValueError(\n                    \"name_or_index must be an int, str, bytes, \"\n                    \"pyarrow.compute.Expression, or list of those\"\n                )\n            return name\n\n        pa_arr = self._data.array._pa_array\n        name = get_name(name_or_index, pa_arr)\n        field_arr = pc.struct_field(pa_arr, name_or_index)\n\n        return Series(\n            field_arr,\n            dtype=ArrowDtype(field_arr.type),\n            index=self._data.index,\n            name=name,\n        )\n\n    def explode(self) -> DataFrame:\n        \"\"\"","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/arrow/accessors.py#L445-L481","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Coerce numeric selectors to int before calling: s.struct.field(int(field_idx)).","Pass the struct field name as a str: s.struct.field('my_field').","For nested struct access, pass a list of int/str such as s.struct.field([0, 'child']).","If building a pyarrow expression, pass pc.struct_field(...) style Expression objects directly."],"exampleFix":"# before\nidx = payload['field']  # may be 2.5 or None from JSON\ns.struct.field(idx)\n# after\nidx = payload['field']\nassert isinstance(idx, (int, str, bytes)), f'bad field selector {idx!r}'\ns.struct.field(int(idx) if isinstance(idx, (int, float)) and float(idx).is_integer() else idx)","handlingStrategy":"validation","validationCode":"import pyarrow.compute as pc\n\ndef valid_struct_field(x):\n    return (\n        isinstance(x, (int, str, bytes))\n        or isinstance(x, pc.Expression)\n        or (hasattr(x, '__iter__') and all(isinstance(i, (int, str, bytes, pc.Expression)) for i in x))\n    )\n\n# before: s.struct.field(selector)\nassert valid_struct_field(selector), f'invalid field selector {selector!r}'\ns.struct.field(selector)","typeGuard":"from typing import Union, List\nimport pyarrow.compute as pc\n\nStructFieldSelector = Union[int, str, bytes, pc.Expression, List[Union[int, str, bytes, pc.Expression]]]\n\ndef is_struct_field_selector(x) -> bool:\n    if isinstance(x, (int, str, bytes, pc.Expression)):\n        return True\n    if hasattr(x, '__iter__') and not isinstance(x, (str, bytes)):\n        return all(isinstance(i, (int, str, bytes, pc.Expression)) for i in x)\n    return False","tryCatchPattern":"try:\n    col = s.struct.field(selector)\nexcept ValueError as e:\n    if 'name_or_index must be' in str(e):\n        raise ValueError(f'Bad struct field selector {selector!r}; expected int/str/bytes/Expression/list') from e\n    raise","preventionTips":["Always normalize numeric field selectors to int before passing.","Validate user-supplied field selectors against the accepted type tuple.","Prefer field names (str) over indices for readability and schema robustness."],"tags":["pyarrow","struct-accessor","input-validation","indexing"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}