pola-rs/polars · error · TypeError

"extract_groups" expects a `str`, given a {qualified_type_na

Error message

"extract_groups" expects a `str`, given a {qualified_type_name(pattern)!r}

What it means

Expr.str.extract_groups returns a struct whose field names come from the named capture groups of the pattern, so the regex must be a literal Python str known at plan-build time. Passing an Expr, Series, bytes, or None raises this TypeError before execution. Column-driven patterns belong to the other extractors in the same namespace.

Source

Thrown at py-polars/src/polars/expr/string.py:1750

        >>> (
        ...     df.with_columns(
        ...         captures=pl.col("url").str.extract_groups(pattern)
        ...     ).with_columns(name=pl.col("captures").struct["1"].str.to_uppercase())
        ... )
        shape: (3, 3)
        ┌─────────────────────────────────┬───────────────────────┬──────────┐
        │ url                             ┆ captures              ┆ name     │
        │ ---                             ┆ ---                   ┆ ---      │
        │ str                             ┆ struct[2]             ┆ str      │
        ╞═════════════════════════════════╪═══════════════════════╪══════════╡
        │ http://vote.com/ballon_dor?can… ┆ {"messi","python"}    ┆ MESSI    │
        │ http://vote.com/ballon_dor?can… ┆ {"weghorst","polars"} ┆ WEGHORST │
        │ http://vote.com/ballon_dor?err… ┆ {null,null}           ┆ null     │
        └─────────────────────────────────┴───────────────────────┴──────────┘
        """
        if not isinstance(pattern, str):
            msg = f'"extract_groups" expects a `str`, given a {qualified_type_name(pattern)!r}'
            raise TypeError(msg)
        return wrap_expr(self._pyexpr.str_extract_groups(pattern))

    def count_matches(self, pattern: str | Expr, *, literal: bool = False) -> Expr:
        r"""
        Count all successive non-overlapping regex matches.

        .. engine-support:: in-memory, streaming, distributed

        Parameters
        ----------
        pattern
            A valid regular expression pattern, compatible with the `regex crate
            <https://docs.rs/regex/latest/regex/>`_.
        literal
            Treat `pattern` as a literal string, not as a regular expression.

        Returns
        -------

View on GitHub (pinned to df599052da)

Solutions

  1. Pass the regex as a plain string with named groups: .str.extract_groups(r'(?P<year>\d{4})-(?P<month>\d{2})')
  2. If patterns live in a column, use .str.extract_many(pl.col('patterns')) or map_batches with Python re
  3. Decode bytes patterns to str before calling

Example fix

# before
pl.col('url').str.extract_groups(pl.col('pattern_col'))

# after (literal pattern)
pl.col('url').str.extract_groups(r'(?P<host>[^/]+)/(?P<path>.*)')

# after (per-row patterns)
pl.col('url').str.extract_many(pl.col('pattern_col'))
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(pattern, str):
    pattern = str(pattern)  # or raise your own error
expr = pl.col('url').str.extract_groups(pattern)

Type guard

def is_literal_pattern(x: object) -> bool:
    return isinstance(x, str)

Prevention

When it happens

Trigger: .str.extract_groups(pl.col('pattern')) or passing a Series of patterns; pattern stored as bytes; pattern=None from optional config; mixing this method up with extract/extract_many which do accept pattern columns.

Common situations: Patterns loaded from a config table or another column; serialized bytes patterns; refactoring code between extract_groups (literal regex, struct output) and extract_many (per-row pattern lists).

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/b863b73a6b188fae. Report an issue: GitHub.