pathwaycom/pathway · error · ValueError
join condition should be of form <left_table>.<column> == <r
Error message
join condition should be of form <left_table>.<column> == <right_table>.<column>
What it means
validate_shape enforces the structural contract of join conditions: cond must be a ColumnBinaryOpExpression using the == operator with a ColumnReference on each side (left, right). Anything else — a single column, <, <=, .isna(), a function call, chained comparisons — raises ValueError demanding the <left_table>.<column> == <right_table>.<column> form.
Source
Thrown at python/pathway/internals/joins.py:1131
columns_mapping,
left_table,
right_table,
left,
right,
substitution,
common_column_names,
mode,
)
def validate_shape(cond: expr.ColumnExpression) -> expr.ColumnBinaryOpExpression:
if (
not isinstance(cond, expr.ColumnBinaryOpExpression)
or cond._operator != op.eq
or not isinstance(cond._left, expr.ColumnReference)
or not isinstance(cond._right, expr.ColumnReference)
):
raise ValueError(
"join condition should be of form <left_table>.<column> == <right_table>.<column>"
)
return cond
def validate_join_condition(
cond: expr.ColumnExpression, left: Table, right: Table
) -> tuple[expr.ColumnReference, expr.ColumnReference, expr.ColumnBinaryOpExpression]:
cond = validate_shape(cond)
try:
eval_type(cond)
except TypeError:
raise TypeError(
"Incompatible types in a join condition.\n"
+ f"The types are: {eval_type(cond._left)} and {eval_type(cond._right)}. "
+ "You might try casting the respective columns to Any type to circumvent this,"
+ " but this is most probably an error."
)View on GitHub (pinned to fa2f74a464)
Solutions
- Rewrite the condition as a single equality between two column references
- Pass multiple equality conditions as separate arguments: t1.join(t2, t1.a == t2.a, t1.c == t2.c)
- For non-equality logic, pre-filter tables or apply the predicate in a later select/with_columns step
Example fix
# before res = t1.join(t2, (t1.a == t2.a) & (t1.c == t2.c)) # after res = t1.join(t2, t1.a == t2.a, t1.c == t2.c)
Defensive patterns
Strategy: type-guard
Validate before calling
from pathway.internals import expr, op
def is_eq_of_refs(cond) -> bool:
return (
isinstance(cond, expr.ColumnBinaryOpExpression)
and cond._operator == op.eq
and isinstance(cond._left, expr.ColumnReference)
and isinstance(cond._right, expr.ColumnReference)
) Type guard
from pathway.internals import expr, op
def is_valid_join_condition(cond) -> bool:
return (
isinstance(cond, expr.ColumnBinaryOpExpression)
and cond._operator == op.eq
and isinstance(cond._left, expr.ColumnReference)
and isinstance(cond._right, expr.ColumnReference)
) Prevention
- One equality per argument; pass multiple conditions as separate *on args, never combined with &
- Non-equality predicates belong in filter/where or a post-join with_columns
When it happens
Trigger: t1.join(t2, t1.a) (bare column); t1.join(t2, t1.a < t2.b); t1.join(t2, (t1.a == t2.a) & (t1.c == t2.c)) — multiple conditions must be passed as separate *on args, not combined with &.
Common situations: SQL/pandas merge habits with arbitrary boolean predicates; trying compound conditions with & instead of varargs; inequality joins (unsupported).
Related errors
- The boolean condition is not properly ordered. The left part
- Left part of a join condition has to be a reference to a tab
- Right part of a join condition has to be a reference to a ta
- Join received extra kwargs. You probably want to use TableLi
- You cannot use {dep.to_column_expression()} in this reduce s
AI-assisted analysis of pathwaycom/pathway@fa2f74a464 (2026-08-15).
Data as JSON: /api/errors/bc1d2f7f071d6f93.
Report an issue: GitHub.