pola-rs/polars · error · ValueError
cannot use 'on' in conjunction with 'left_on' or 'right_on'
Error message
cannot use 'on' in conjunction with 'left_on' or 'right_on'
What it means
LazyFrame.join() raises ValueError when on= is combined with left_on= or right_on=. on= means 'the same key on both frames'; left_on/right_on exist precisely for differing keys, so specifying both is ambiguous.
Source
Thrown at py-polars/src/polars/lazyframe/frame.py:6426
│ 2 ┆ 7.0 ┆ b ┆ y ┆ b │
│ 2 ┆ 7.0 ┆ b ┆ z ┆ d │
│ 3 ┆ 8.0 ┆ c ┆ x ┆ a │
│ 3 ┆ 8.0 ┆ c ┆ y ┆ b │
│ 3 ┆ 8.0 ┆ c ┆ z ┆ d │
└─────┴─────┴─────┴───────┴───────────┘
"""
require_same_type(self, other)
if maintain_order is None:
maintain_order = "none"
uses_on = on is not None
uses_left_on = left_on is not None
uses_right_on = right_on is not None
uses_lr_on = uses_left_on or uses_right_on
if uses_on and uses_lr_on:
msg = "cannot use 'on' in conjunction with 'left_on' or 'right_on'"
raise ValueError(msg)
elif uses_left_on != uses_right_on:
msg = "'left_on' requires corresponding 'right_on'"
raise ValueError(msg)
if how == "outer":
how = "full"
issue_deprecation_warning(
"use of `how='outer'` should be replaced with `how='full'`.",
version="0.20.29",
)
elif how == "outer_coalesce": # type: ignore[comparison-overlap]
coalesce = True
how = "full"
issue_deprecation_warning(
"use of `how='outer_coalesce'` should be replaced with `how='full', coalesce=True`.",
version="0.20.29",
)
elif how == "cross":View on GitHub (pinned to df599052da)
Solutions
- Use on='id' alone when key names are identical
- Use left_on= and right_on= alone (both required) when names differ
- In wrappers, use sentinel logic so exactly one of the two styles is passed: kwargs.pop('on', None) before setting left_on/right_on
Example fix
# before lf.join(other, on='id', left_on='id', right_on='user_id') # after lf.join(other, left_on='id', right_on='user_id')
Defensive patterns
Strategy: validation
Validate before calling
if on is not None:
assert left_on is None and right_on is None, 'do not mix on= with left_on/right_on='
kwargs = {'on': on}
else:
kwargs = {'left_on': left_on, 'right_on': right_on}
lf.join(other, **kwargs, how=how) Type guard
def uses_exclusive_join_keys(on, left_on, right_on) -> bool:
return not (on is not None and (left_on is not None or right_on is not None)) Prevention
- Choose one key style per call site and stick to it
- In wrappers, normalize inputs to a single (left_keys, right_keys) pair
- Use on= None default so stale values don't linger
When it happens
Trigger: lf.join(other, on='id', left_on='id') (redundant specification); refactors that added left_on/right_on without removing an existing on=; option dicts that always set on plus per-side keys.
Common situations: Parameterized join wrappers where on has a default value that is not cleared; incremental edits to join calls.
Related errors
- 'left_on' requires corresponding 'right_on'
- cross join should not pass join keys
- must specify `on` OR `left_on` and `right_on`
- negative stop is not supported for lazy slices
- negative stride is not supported in conjunction with start+s
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/ff15c0c5cd77a7de.
Report an issue: GitHub.