pathwaycom/pathway · error · ValueError

Expected a ColumnReference, found a string. Did you mean <ta

Error message

Expected a ColumnReference, found a string. Did you mean <table>.{arg} instead of {repr(arg)}?

What it means

groupby() validates every positional argument is an expr.ColumnReference. Strings are given a dedicated message: ValueError('Expected a ColumnReference, found a string...') suggesting the attribute-access form. The guard exists because strings are silently meaningful in other APIs (e.g. __getitem__) and would otherwise be mistaken for column names here.

Source

Thrown at python/pathway/internals/table.py:1252

            args = (*args, instance)
        if id is not None:
            if len(args) == 0:
                args = (id,)
            elif len(args) > 1:
                raise ValueError(
                    "Table.groupby() cannot have id argument when grouping by multiple columns."
                )
            elif args[0]._column != id._column:
                raise ValueError(
                    "Table.groupby() received id argument and is grouped by a single column,"
                    + " but the arguments are not equal.\n"
                    + "Consider using <table>.groupby(id=...), skipping the positional argument."
                )

        for arg in args:
            if not isinstance(arg, expr.ColumnReference):
                if isinstance(arg, str):
                    raise ValueError(
                        f"Expected a ColumnReference, found a string. Did you mean <table>.{arg}"
                        + f" instead of {repr(arg)}?"
                    )
                else:
                    raise ValueError(
                        "All Table.groupby() arguments have to be a ColumnReference."
                    )

        self._check_for_disallowed_types(*args)
        return groupbys.GroupedTable.create(
            table=self,
            grouping_columns=args,
            last_column_is_instance=instance is not None,
            set_id=id is not None,
            sort_by=sort_by,
            _filter_out_results_of_forgetting=_filter_out_results_of_forgetting,
            _skip_errors=_skip_errors,
            _is_window=_is_window,

View on GitHub (pinned to fa2f74a464)

Solutions

  1. Use attribute access: t.groupby(t.owner) or t.groupby(pw.this.owner)
  2. Convert stored names via getattr: t.groupby(*(getattr(t, name) for name in names))
  3. For multiple columns pass each as a reference: t.groupby(t.a, t.b)

Example fix

# before
g = t.groupby('owner')  # string -> ValueError

# after
g = t.groupby(t.owner)
# dynamic names:
g = t.groupby(*(getattr(t, n) for n in ['owner', 'pet']))
Defensive patterns

Strategy: type-guard

Validate before calling

from pathway.internals import expression as expr

def all_column_refs(args) -> bool:
    return all(isinstance(a, expr.ColumnReference) for a in args)

Type guard

from pathway.internals import expression as expr

def is_column_ref(arg) -> bool:
    return isinstance(arg, expr.ColumnReference)

Prevention

When it happens

Trigger: t.groupby('owner') or t.groupby(['a','b']) — passing column names as strings or a list of strings instead of ColumnReference objects such as t.owner / pw.this.owner.

Common situations: Coming from pandas/Spark where groupby('col') is idiomatic; storing column names in config and forwarding them directly.

Related errors


AI-assisted analysis of pathwaycom/pathway@fa2f74a464 (2026-08-15). Data as JSON: /api/errors/e89ac42c482ef568. Report an issue: GitHub.