{"record":{"id":"0f78a0162256ac31","repo":"pathwaycom/pathway","slug":"expected-a-columnreference-found-a-string-did-yo-0f78a0","errorCode":null,"errorMessage":"Expected a ColumnReference, found a string. Did you mean this.{arg} instead of {repr(arg)}?","messagePattern":"Expected a ColumnReference, found a string\\. Did you mean this\\.(.+?) instead of (.+?)\\?","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/pathway/internals/joins.py","lineNumber":850,"sourceCode":"        ... 3    80  Alice    2\n        ... ''')\n        >>> t2 = pw.debug.table_from_markdown('''\n        ...     cost  owner  pet size\n        ... 11   100  Alice    3    M\n        ... 12    90    Bob    1    L\n        ... 13    80    Tom    1   XL\n        ... ''')\n        >>> result = (t1.join(t2, t1.owner==t2.owner).groupby(pw.this.owner)\n        ...     .reduce(pw.this.owner, pairs = pw.reducers.count()))\n        >>> pw.debug.compute_and_print(result, include_id=False)\n        owner | pairs\n        Alice | 2\n        Bob   | 1\n        \"\"\"\n        for arg in args:\n            if not isinstance(arg, expr.ColumnReference):\n                if isinstance(arg, str):\n                    raise ValueError(\n                        f\"Expected a ColumnReference, found a string. Did you mean this.{arg} instead of {repr(arg)}?\"\n                    )\n                else:\n                    raise ValueError(\n                        \"In JoinResult.groupby() all arguments have to be a ColumnReference.\"\n                    )\n        from pathway.internals.groupbys import GroupedJoinResult\n\n        return GroupedJoinResult(\n            _join_result=self,\n            _args=args,\n            _id=id,\n        )\n\n    @trace_user_frame\n    @desugar\n    @arg_handler(handler=reduce_args_handler)\n    def reduce(","sourceCodeStart":832,"sourceCodeEnd":868,"githubUrl":"https://github.com/pathwaycom/pathway/blob/fa2f74a4649b7c5908690cf60137263d8d80de5f/python/pathway/internals/joins.py#L832-L868","documentation":"JoinResult.groupby validates every positional argument: it must be an expr.ColumnReference. When a plain Python str is passed instead, ValueError suggests the likely intended form this.<arg> — e.g. groupby('owner') should be groupby(pw.this.owner) or table.owner. The string-specific branch exists purely to give an actionable hint.","triggerScenarios":"result = t1.join(t2, ...).groupby('colname') — passing column names as strings, as pandas/SQL allow.","commonSituations":"Porting pandas merge+groupby code; dynamically building groupby lists from string column names; muscle memory from dataframe APIs.","solutions":["Replace the string with a ColumnReference: pw.this.<col> or <table>.<col>","When building dynamically, map names through getattr(table, name) instead of passing raw strings"],"exampleFix":"# before\nres = t1.join(t2, t1.owner == t2.owner).groupby('owner')\n\n# after\nres = t1.join(t2, t1.owner == t2.owner).groupby(pw.this.owner)","handlingStrategy":"type-guard","validationCode":"from pathway.internals import expr\n\ndef to_refs(table, names):\n    refs = [getattr(table, n) if isinstance(n, str) else n for n in names]\n    assert all(isinstance(r, expr.ColumnReference) for r in refs)\n    return refs","typeGuard":"from pathway.internals import expr\n\ndef is_column_reference(x) -> bool:\n    return isinstance(x, expr.ColumnReference)","tryCatchPattern":null,"preventionTips":["Never pass strings for columns in Pathway; always pw.this.<col> or table.<col>","Convert dynamic string column lists via getattr(table, name) before calling groupby/reduce"],"tags":["pathway","join","groupby","api-misuse","type-error"],"backgroundTag":null,"analyzedSha":"fa2f74a4649b7c5908690cf60137263d8d80de5f","analyzedAt":"2026-08-15T01:48:17.006Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}