pola-rs/polars · error

expected `on` to be str or Expr, got {qualified_type_name(on

Error message

expected `on` to be str or Expr, got {qualified_type_name(on)!r}

What it means

In DataFrame.join_asof, the `on` parameter (used when both frames key on the same column) must be a single column name (str) or a pl.Expr. Unlike DataFrame.join, asof joining does not accept lists, tuples, pl.Series, or other objects for `on`, so polars validates up front and raises TypeError naming the offending type.

Source

Thrown at py-polars/src/polars/dataframe/frame.py:8221

        │ ---         ┆ ---        ┆ ---        ┆ ---  │
        │ str         ┆ date       ┆ f64        ┆ i64  │
        ╞═════════════╪════════════╪════════════╪══════╡
        │ Germany     ┆ 2016-03-01 ┆ 82.19      ┆ 4164 │
        │ Germany     ┆ 2018-08-01 ┆ 82.66      ┆ 4696 │
        │ Germany     ┆ 2019-01-01 ┆ 83.12      ┆ 4696 │
        │ Netherlands ┆ 2016-03-01 ┆ 17.11      ┆ 784  │
        │ Netherlands ┆ 2018-08-01 ┆ 17.32      ┆ 910  │
        │ Netherlands ┆ 2019-01-01 ┆ 17.4       ┆ 910  │
        └─────────────┴────────────┴────────────┴──────┘
        """
        require_same_type(self, other)

        if on is not None:
            if not isinstance(on, (str, pl.Expr)):
                msg = (
                    f"expected `on` to be str or Expr, got {qualified_type_name(on)!r}"
                )
                raise TypeError(msg)
        else:
            if not isinstance(left_on, (str, pl.Expr)):
                msg = f"expected `left_on` to be str or Expr, got {qualified_type_name(left_on)!r}"
                raise TypeError(msg)
            elif not isinstance(right_on, (str, pl.Expr)):
                msg = f"expected `right_on` to be str or Expr, got {qualified_type_name(right_on)!r}"
                raise TypeError(msg)

        from polars.lazyframe.opt_flags import QueryOptFlags

        return (
            self.lazy()
            .join_asof(
                other.lazy(),
                left_on=left_on,
                right_on=right_on,
                on=on,
                by_left=by_left,

View on GitHub (pinned to df599052da)

Solutions

  1. Pass a single key: df.join_asof(other, on='time') or on=pl.col('time')
  2. For differently named keys on each side, use left_on/right_on instead of on
  3. For a multi-key asof join, keep `on` as the single sorted time key and add by='id' (or by=['id', ...]) for the extra keys
  4. Replace any pl.Series/numpy value with the name or pl.col(...) of the column it came from — the key must be a column, not data

Example fix

# before
out = quotes.join_asof(trades, on=['date', 'ticker'])

# after
out = quotes.sort('date').join_asof(trades.sort('date'), on='date', by='ticker')
Defensive patterns

Strategy: type-guard

Validate before calling

from polars.expr import Expr

if not isinstance(on, (str, Expr)):
    raise TypeError(f'join_asof `on` must be a single str or Expr, got {type(on)!r}')

Type guard

from polars.expr import Expr

def is_single_asof_key(v: object) -> bool:
    return isinstance(v, (str, Expr))

Prevention

When it happens

Trigger: df.join_asof(other, on=['time', 'id']); on=('time',); on=pl.Series(values) (e.g. timestamps computed inline); passing a numpy array or a datetime value instead of a column reference.

Common situations: Assuming join_asof shares DataFrame.join's multi-column `on` grammar; porting pandas merge_asof code; attempting a multi-key asof join by passing several names; confusing the key column with a value array.

Related errors


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