pola-rs/polars · error · ValueError

left join column not found

Error message

left join column {name!r} not found

What it means

Raised as a ValueError when a column named in `left_on` does not exist in the left frame's schema. The check runs against collect_schema() before the join executes, failing eagerly and naming the offending column.

Solutions

  1. Verify the column exists via `lf.collect_schema().names()` and fix the name.
  2. Add the column upstream via `with_columns`/`rename` before joining.
  3. Check that preceding select/drop/rename steps did not remove the key column.

Example fix

// before
lf.join(other, left_on="cust_id", right_on="id")  # 'cust_id' missing
// after
lf = lf.rename({"customer_id": "cust_id"})
lf.join(other, left_on="cust_id", right_on="id")
Defensive patterns

Strategy: validation

Validate before calling

left_schema = lf.collect_schema()
missing = [c for c in left_on if c not in left_schema]
if missing:
    raise ValueError(f"left frame missing join columns: {missing}")

Try / catch

try:
    out = lf.join(other, left_on=left_on, right_on=right_on, how=how)
except ValueError as e:
    if "left join column" in str(e):
        raise KeyError(f"left frame columns: {lf.collect_schema().names()}") from e
    raise

Prevention

When it happens

Trigger: Calling `lf.join(other, left_on="cust_id", ...)` where the left frame has no column 'cust_id' (renamed, dropped, or misspelled).

Common situations: Upstream column renames; lazy frame schema differing from what the join assumes; typos in column names.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

                    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()
        for name in right_on:
            if name not in right_schema:
                msg = f"right join column {name!r} not found"
                raise ValueError(msg)

        # no need to join if *only* join columns are in other (inner/left update only)
        if how != "full" and len(right_schema) == len(right_on):
            if row_index_name is not None:
                return self.drop(row_index_name)
            return self

        # only use non-idx right columns present in left frame
        right_other = set(right_schema).intersection(left_schema) - set(right_on)

        # When include_nulls is True, we need to distinguish records after the join that
        # were originally null in the right frame, as opposed to records that were null
        # because the key was missing from the right frame.

View on GitHub (pinned to fe841f959e)