{"record":{"id":"6caaf8de218c5d59","repo":"pathwaycom/pathway","slug":"received-how-argument-of-join-that-is-a-string","errorCode":null,"errorMessage":"Received `how` argument of join that is a string.\nYou probably want to use one of JoinMode.INNER, JoinMode.LEFT, JoinMode.RIGHT or JoinMode.OUTER values.","messagePattern":"Received `how` argument of join that is a string\\.\nYou probably want to use one of JoinMode\\.INNER, JoinMode\\.LEFT, JoinMode\\.RIGHT or JoinMode\\.OUTER values\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/pathway/internals/arg_handlers.py","lineNumber":87,"sourceCode":"    }\n\n\ndef join_kwargs_handler(*, allow_how: bool, allow_id: bool):\n    def handler(self, other, *on, **kwargs):\n        processed_kwargs = {}\n        if \"how\" in kwargs:\n            how = kwargs.pop(\"how\")\n            processed_kwargs[\"how\"] = how\n            if not allow_how:\n                raise ValueError(\n                    \"Received `how` argument but was not expecting any.\\n\"\n                    + \"Consider using a generic join method that handles `how` \"\n                    + \"to decide on a type of a join to be used.\"\n                )\n            elif isinstance(how, JoinMode):\n                pass\n            elif isinstance(how, str):\n                raise ValueError(\n                    \"Received `how` argument of join that is a string.\\n\"\n                    + \"You probably want to use one of \"\n                    + \"JoinMode.INNER, JoinMode.LEFT, JoinMode.RIGHT or JoinMode.OUTER values.\"\n                )\n            else:\n                raise ValueError(\n                    \"How argument of join should be one of \"\n                    + \"JoinMode.INNER, JoinMode.LEFT, JoinMode.RIGHT or JoinMode.OUTER values.\"\n                )\n\n        if \"id\" in kwargs:\n            id = kwargs.pop(\"id\")\n            processed_kwargs[\"id\"] = id\n            if not allow_id:\n                raise ValueError(\n                    \"Received `id` argument but was not expecting any.\\n\"\n                    + \"Not every join type supports `id` argument.\"\n                )","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/internals/arg_handlers.py#L69-L105","documentation":"Where a join does accept 'how', Pathway requires a JoinMode enum member (pw.JoinMode.INNER/LEFT/RIGHT/OUTER) rather than a bare string like 'left'. Strings are error-prone (case, typos, aliases), so the shared join kwargs handler raises this ValueError when it sees isinstance(how, str) and lists the accepted enum values.","triggerScenarios":"t1.join(t2, t1.k == t2.k, how='left'); how='inner'; how read from a config string and passed through unconverted.","commonSituations":"pandas/Spark/SQL habits where how is a string; join type supplied via CLI flag or YAML config; older Pathway examples or tutorials that used string modes.","solutions":["Use the enum: how=pw.JoinMode.LEFT (INNER, LEFT, RIGHT, OUTER).","Map config strings once at load: {'inner': pw.JoinMode.INNER, ...}[cfg['join_type']].","Or use the dedicated methods join_inner/join_left/join_right/join_outer which need no how at all."],"exampleFix":"# before\nt1.join(t2, t1.k == t2.k, how=\"left\")\n\n# after\nt1.join(t2, t1.k == t2.k, how=pw.JoinMode.LEFT)","handlingStrategy":"type-guard","validationCode":"import pathway as pw\n\nmode_str = cfg[\"join_type\"]\nmode_map = {\n    \"inner\": pw.JoinMode.INNER,\n    \"left\": pw.JoinMode.LEFT,\n    \"right\": pw.JoinMode.RIGHT,\n    \"outer\": pw.JoinMode.OUTER,\n}\ntry:\n    how = mode_map[mode_str.lower()]\nexcept KeyError:\n    raise ValueError(f\"unknown join mode {mode_str!r}; expected one of {list(mode_map)}\")","typeGuard":"import pathway as pw\n\ndef is_join_mode(v) -> bool:\n    return isinstance(v, pw.JoinMode)","tryCatchPattern":null,"preventionTips":["Never pass bare strings as how; always pw.JoinMode.*.","Centralize string-to-enum mapping for config-supplied join modes.","Prefer the dedicated join_inner/join_left/... methods to skip how entirely."],"tags":["join","api-misuse","enum"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}