pola-rs/polars · error · ValueError

must specify `on` OR `left_on` and `right_on`

Error message

must specify `on` OR `left_on` and `right_on`

What it means

LazyFrame.join() needs join keys: either `on` alone, or `left_on` together with `right_on`. If none of these is provided (and the strategy isn't 'cross'), there is no way to match rows, so a ValueError is raised.

Solutions

  1. Add on='key' when the key column name matches in both frames
  2. Or add left_on='lkey', right_on='rkey' for differently named keys
  3. For multiple keys pass lists: on=['a','b'] or left_on=[...], right_on=[...]

Example fix

// before
df.join(other, how='left')
// after
df.join(other, on='id', how='left')
Defensive patterns

Strategy: validation

Validate before calling

def require_keys(on, left_on, right_on, how):
    if how != 'cross' and on is None and left_on is None and right_on is None:
        raise ValueError('join requires on= or left_on/right_on=')

Type guard

def has_join_keys(on, left_on, right_on) -> bool:
    return on is not None or (left_on is not None and right_on is not None)

Try / catch

try:
    out = df.join(other, on=key, how=how)
except ValueError as e:
    if 'must specify `on` OR' in str(e):
        raise KeyError('join() needs on= or left_on/right_on= arguments') from e
    raise

Prevention

When it happens

Trigger: Calling lf.join(other) or lf.join(other, how='inner') with no key arguments; also passing only `by`-style auxiliary parameters meant for join_asof.

Common situations: Porting pandas code that merges on indexes; forgetting keys after refactoring; copying a cross-join call (which omits keys legally) and then adding a non-cross `how`.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/a347c532bc8cb906. Report an issue: GitHub.

Appendix: source

Thrown at py-polars/src/polars/lazyframe/frame.py:6267

                    how,
                    suffix,
                    validate,
                    maintain_order,
                    build_side=build_side,
                    coalesce=None,
                )
            )

        if uses_on:
            pyexprs = parse_into_list_of_expressions(on)
            pyexprs_left = pyexprs
            pyexprs_right = pyexprs
        elif uses_lr_on:
            pyexprs_left = parse_into_list_of_expressions(left_on)
            pyexprs_right = parse_into_list_of_expressions(right_on)
        else:
            msg = "must specify `on` OR `left_on` and `right_on`"
            raise ValueError(msg)

        return self._from_pyldf(
            self._ldf.join(
                other._ldf,
                pyexprs_left,
                pyexprs_right,
                allow_parallel,
                force_parallel,
                nulls_equal,
                how,
                suffix,
                validate,
                maintain_order,
                build_side,
                coalesce,
            )
        )

View on GitHub (pinned to fe841f959e)