pola-rs/polars · error · TypeError

invalid dtype: {t!r}

Error message

invalid dtype: {t!r}

What it means

Thrown inside cs.by_dtype (py-polars/src/polars/selectors.py:1094) when an ELEMENT of a collection argument is not a Polars DataType and not a plain Python type. by_dtype accepts dtypes, Python classes (e.g. int, str), and collections thereof; a non-dtype item inside a list/tuple (such as the string "float" or the int 5) fails this inner check with TypeError.

Source

Thrown at py-polars/src/polars/selectors.py:1094

    shape: (2, 2)
    ┌───────┬──────────┐
    │ other ┆ value    │
    │ ---   ┆ ---      │
    │ str   ┆ i64      │
    ╞═══════╪══════════╡
    │ bar   ┆ 5000555  │
    │ foo   ┆ -3265500 │
    └───────┴──────────┘
    """
    all_dtypes: builtins.list[PolarsDataType | PythonDataType] = []
    for tp in dtypes:
        if is_polars_dtype(tp) or isinstance(tp, type):
            all_dtypes.append(tp)
        elif isinstance(tp, Collection):
            for t in tp:
                if not (is_polars_dtype(t) or isinstance(t, type)):
                    msg = f"invalid dtype: {t!r}"
                    raise TypeError(msg)
                all_dtypes.append(t)
        else:
            msg = f"invalid dtype: {tp!r}"
            raise TypeError(msg)

    return Selector._by_dtype(all_dtypes)


def by_index(
    *indices: int | range | Sequence[int | range], require_all: bool = True
) -> Selector:
    """
    Select all columns matching the given indices (or range objects).

    Parameters
    ----------
    *indices
        One or more column indices (or range objects).

View on GitHub (pinned to df599052da)

Solutions

  1. Use actual Polars dtypes: cs.by_dtype([pl.Int64, pl.Float64]) — or Python classes: cs.by_dtype([int, float])
  2. Map config strings to dtypes before calling: dtypes = [CONFIG_DTYPES[s] for s in config["dtypes"]] with CONFIG_DTYPES = {"int": pl.Int64, "float": pl.Float64, ...}
  3. Filter out invalid entries from dynamic lists: [d for d in lst if is_polars_dtype(d) or isinstance(d, type)]

Example fix

# before
sel = cs.by_dtype([pl.Int64, "float"])  # "float" is a str, not a dtype

# after
sel = cs.by_dtype([pl.Int64, pl.Float64])
# or with Python classes
sel = cs.by_dtype([pl.Int64, float])
Defensive patterns

Strategy: type-guard

Validate before calling

from polars import selectors as cs

def valid_dtype(d: object) -> bool:
    import polars as pl
    return pl.api.is_polars_dtype(d) or isinstance(d, type)

dtypes = [d for d in config["dtypes"] if valid_dtype(d)]
sel = cs.by_dtype(dtypes)

Type guard

from typing import TypeGuard

def is_dtype_arg(item: object) -> TypeGuard[object]:
    import polars as pl
    return pl.api.is_polars_dtype(item) or isinstance(item, type)

Try / catch

try:
    sel = cs.by_dtype(raw_list)
except TypeError as e:
    if "invalid dtype" in str(e):
        bad = [d for d in raw_list if not (pl.api.is_polars_dtype(d) or isinstance(d, type))]
        raise ValueError(f"invalid dtypes in config: {bad!r}") from e
    raise

Prevention

When it happens

Trigger: cs.by_dtype([pl.Int64, "float"]) (string instead of pl.Float64), cs.by_dtype([pl.Int64, 5]), or cs.by_dtype([pl.Int64, None]). The OUTER item is a valid collection, but one element inside is neither a DataType nor a class.

Common situations: Passing dtype names as strings loaded from JSON/YAML config, or writing shorthand like "str"/"float" instead of pl.String/pl.Float64. Also mixing results of type(...) calls or None placeholders into dtype lists.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/53496cbf6b8326d9. Report an issue: GitHub.