{"record":{"id":"e1c7935426fe3e9c","repo":"pola-rs/polars","slug":"left-on-requires-corresponding-right-on","errorCode":null,"errorMessage":"'left_on' requires corresponding 'right_on'","messagePattern":"'left_on' requires corresponding 'right_on'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/lazyframe/frame.py","lineNumber":6429,"sourceCode":"        │ 3   ┆ 8.0 ┆ c   ┆ y     ┆ b         │\n        │ 3   ┆ 8.0 ┆ c   ┆ z     ┆ d         │\n        └─────┴─────┴─────┴───────┴───────────┘\n        \"\"\"\n        require_same_type(self, other)\n\n        if maintain_order is None:\n            maintain_order = \"none\"\n\n        uses_on = on is not None\n        uses_left_on = left_on is not None\n        uses_right_on = right_on is not None\n        uses_lr_on = uses_left_on or uses_right_on\n        if uses_on and uses_lr_on:\n            msg = \"cannot use 'on' in conjunction with 'left_on' or 'right_on'\"\n            raise ValueError(msg)\n        elif uses_left_on != uses_right_on:\n            msg = \"'left_on' requires corresponding 'right_on'\"\n            raise ValueError(msg)\n\n        if how == \"outer\":\n            how = \"full\"\n            issue_deprecation_warning(\n                \"use of `how='outer'` should be replaced with `how='full'`.\",\n                version=\"0.20.29\",\n            )\n        elif how == \"outer_coalesce\":  # type: ignore[comparison-overlap]\n            coalesce = True\n            how = \"full\"\n            issue_deprecation_warning(\n                \"use of `how='outer_coalesce'` should be replaced with `how='full', coalesce=True`.\",\n                version=\"0.20.29\",\n            )\n        elif how == \"cross\":\n            if uses_on or uses_lr_on:\n                msg = \"cross join should not pass join keys\"\n                raise ValueError(msg)","sourceCodeStart":6411,"sourceCodeEnd":6447,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/lazyframe/frame.py#L6411-L6447","documentation":"LazyFrame.join() requires left_on= and right_on= to be supplied as a pair. Passing only one of them raises ValueError, because a join needs a key for each side.","triggerScenarios":"lf.join(other, left_on='id') missing right_on; conditional code that sets right_on only in one branch; typo'd parameter name (right_onn=...) leaving right_on as None.","commonSituations":"Asymmetric joins where the developer only thinks about the left frame; copy-paste edits that drop one side; dynamically built kwargs.","solutions":["Add the matching right_on='other_id' (or left_on= if that is the missing one)","If key names are identical, simplify to on='key'","When building kwargs dynamically, assert both or neither of left_on/right_on is present"],"exampleFix":"# before\nlf.join(other, left_on='id')\n\n# after\nlf.join(other, left_on='id', right_on='id')","handlingStrategy":"validation","validationCode":"if (left_on is None) != (right_on is None):\n    raise ValueError('left_on and right_on must be passed together')\nlf.join(other, on=on, left_on=left_on, right_on=right_on)","typeGuard":"def has_paired_lr_keys(left_on, right_on) -> bool:\n    return (left_on is None) == (right_on is None)","tryCatchPattern":null,"preventionTips":["Always write left_on and right_on as an adjacent pair when editing joins","Diff-join calls in code review for one-sided key edits"],"tags":["polars","lazyframe","join","missing-argument"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}