pola-rs/polars · error · ValueError

missing join columns for left frame

Error message

missing join columns for left frame

What it means

When neither on nor left_on/right_on is given, join falls back to a row-index join and raises ValueError if it cannot establish the left frame's join columns (e.g. they were dropped or renamed), leaving the left side without keys.

Solutions

  1. Add the matching `left_on="lcol"` argument.
  2. Or use `on="col"` when both frames share the same key column name.
  3. Always supply left_on and right_on together.

Example fix

// before
lf.join(other, right_on="rid")
// after
lf.join(other, left_on="lid", right_on="rid")
Defensive patterns

Strategy: validation

Validate before calling

if on is None and (left_on is None) != (right_on is None):
    raise ValueError("provide both left_on and right_on, or use on")
out = lf.join(other, on=on, left_on=left_on, right_on=right_on, how=how)

Try / catch

try:
    out = lf.join(other, left_on=left_on, right_on=right_on, how=how)
except ValueError as e:
    if "missing join columns" in str(e):
        out = lf.join(other, on=on, how=how)
    else:
        raise

Prevention

When it happens

Trigger: Calling `lf.join(other, right_on="rid")` with `on=None` and `left_on=None` — the 'one of left or right is missing' branch raises.

Common situations: Forgetting `left_on` when key column names differ between frames; partially refactoring from `on=` to `left_on=`/`right_on=`.

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/68fb754765759ac1. Report an issue: GitHub.

Appendix: source

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

            raise ValueError(msg)

        if how not in ("left", "inner", "full"):
            msg = f"`how` must be one of {{'left', 'inner', 'full'}}; found {how!r}"
            raise ValueError(msg)

        row_index_name = None
        if on is None:
            if left_on is None and right_on is None:
                # no keys provided--use row index
                row_index_name = "__POLARS_ROW_INDEX"
                self = self.with_row_index(row_index_name)
                other = other.with_row_index(row_index_name)
                left_on = right_on = [row_index_name]
            else:
                # one of left or right is missing, raise error
                if left_on is None:
                    msg = "missing join columns for left frame"
                    raise ValueError(msg)
                if right_on is None:
                    msg = "missing join columns for right frame"
                    raise ValueError(msg)
        else:
            # move on into left/right_on to simplify logic
            left_on = right_on = on

        if isinstance(left_on, str):
            left_on = [left_on]
        if isinstance(right_on, str):
            right_on = [right_on]

        left_schema = self.collect_schema()
        for name in left_on:
            if name not in left_schema:
                msg = f"left join column {name!r} not found"
                raise ValueError(msg)
        right_schema = other.collect_schema()

View on GitHub (pinned to fe841f959e)