{"record":{"id":"a77dd8c95be97b30","repo":"pola-rs/polars","slug":"expected-type-int-str-got-qualified-type-nam-a77dd8","errorCode":null,"errorMessage":"expected type 'int | str', got {qualified_type_name(item)!r} ({item!r})","messagePattern":"expected type 'int \\| str', got (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/expr/struct.py","lineNumber":75,"sourceCode":"\n        >>> df.select(pl.col(\"s\").struct[0])\n        shape: (2, 1)\n        ┌─────┐\n        │ x   │\n        │ --- │\n        │ i64 │\n        ╞═════╡\n        │ 1   │\n        │ 2   │\n        └─────┘\n        \"\"\"\n        if isinstance(item, str):\n            return self.field(item)\n        elif isinstance(item, int):\n            return wrap_expr(self._pyexpr.struct_field_by_index(item))\n        else:\n            msg = f\"expected type 'int | str', got {qualified_type_name(item)!r} ({item!r})\"\n            raise TypeError(msg)\n\n    def field(self, name: str | list[str], *more_names: str) -> Expr:\n        \"\"\"\n        Retrieve one or multiple `Struct` field(s) as a new Series.\n\n        .. engine-support:: in-memory, streaming, distributed\n\n        Parameters\n        ----------\n        name\n            Name of the struct field to retrieve.\n        *more_names\n            Additional struct field names.\n\n        Examples\n        --------\n        >>> df = pl.DataFrame(\n        ...     {","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/expr/struct.py#L57-L93","documentation":"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.","triggerScenarios":".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')].","commonSituations":"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.","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"],"exampleFix":"# before\nidx = int(np.argmax(counts))\npl.col('s').struct[np.argmax(counts)]\n\n# after\npl.col('s').struct[int(idx)]\n# or, more robustly, by name:\npl.col('s').struct['field_name']","handlingStrategy":"type-guard","validationCode":"item = int(item) if isinstance(item, (int, float)) else item\nif not isinstance(item, (str, int)):\n    raise TypeError(f'bad struct subscript: {item!r}')\nexpr = pl.col('s').struct[item]","typeGuard":"import operator\n\ndef is_struct_key(x: object) -> bool:\n    return isinstance(x, str) or (isinstance(x, int) and not isinstance(x, bool))\n\n# also coerce numpy integers at the boundary:\ndef coerce_struct_key(x: object) -> str | int:\n    if hasattr(x, 'item') and not isinstance(x, (str, bytes)):\n        x = operator.index(x)  # numpy integers support __index__\n    return x  # type: ignore[return-value]","tryCatchPattern":null,"preventionTips":["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[...]"],"tags":["polars","struct","typeerror","subscript","numpy"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}