pandas-dev/pandas · error · ValueError
{pat=} must contain a symbolic group name.
Error message
{pat=} must contain a symbolic group name. What it means
Raised by ArrowExtensionArray._str_extract when the compiled regex has no symbolic (named) groups. The ArrowExtensionArray implementation builds result columns keyed by `re.compile(pat).groupindex.keys()`, so at least one named capture group `(?P<name>...)` is mandatory. An unnamed group or a groupless pattern is rejected with ValueError before any extraction runs.
Source
Thrown at pandas/core/arrays/arrow/array.py:3669
result = self._apply_elementwise(predicate)
return self._from_pyarrow_array(pa.chunked_array(result))
def _str_casefold(self) -> Self:
predicate = lambda val: val.casefold()
result = self._apply_elementwise(predicate)
return self._from_pyarrow_array(pa.chunked_array(result))
def _str_encode(self, encoding: str, errors: str = "strict") -> Self:
predicate = lambda val: val.encode(encoding, errors)
result = self._apply_elementwise(predicate)
return self._from_pyarrow_array(pa.chunked_array(result))
def _str_extract(self, pat: str, flags: int = 0, expand: bool = True):
if flags:
raise NotImplementedError("Only flags=0 is implemented.")
groups = re.compile(pat).groupindex.keys()
if len(groups) == 0:
raise ValueError(f"{pat=} must contain a symbolic group name.")
result = pc.extract_regex(self._pa_array, pat)
if expand:
return {
col: self._from_pyarrow_array(pc.struct_field(result, [i]))
for col, i in zip(groups, range(result.type.num_fields), strict=True)
}
else:
return type(self)(pc.struct_field(result, [0]))
def _str_findall(self, pat: str, flags: int = 0) -> Self:
regex = re.compile(pat, flags=flags)
predicate = lambda val: regex.findall(val)
result = self._apply_elementwise(predicate)
return self._from_pyarrow_array(pa.chunked_array(result))
def _str_get_dummies(self, sep: str = "|", dtype: NpDtype | None = None):
if dtype is None:
dtype = np.bool_View on GitHub (pinned to 71959b8cb9)
Solutions
- Add a symbolic name to the group: `s.str.extract(r"(?P<num>\\d+)")`.
- If you only need a boolean/match, use `s.str.contains(pat)` or `s.str.match(pat)` instead of str.extract.
- If positional columns are required, cast to string[python]/object: `s.astype("string[python]").str.extract(r"(\\d+)")`.
- Name every group when you have multiple captures so each column is addressable.
Example fix
# before s = pd.Series(["a1","b2"], dtype="string[pyarrow]") s.str.extract(r"(\\d+)") # ValueError # after s.str.extract(r"(?P<digit>\\d+)")
Defensive patterns
Strategy: validation
Validate before calling
import re
def has_named_group(pat: str) -> bool:
return len(re.compile(pat).groupindex) > 0
def safe_extract(s, pat):
if not has_named_group(pat):
raise ValueError(f"pattern {pat!r} needs at least one named group (?P<name>...)")
return s.str.extract(pat) Type guard
import re
def is_named_group_pattern(pat: str) -> bool:
try:
return len(re.compile(pat).groupindex) > 0
except re.error:
return False Try / catch
try:
out = s.str.extract(pat)
except ValueError as e:
if "symbolic group name" in str(e):
# add a default name and retry
out = s.str.extract(f"(?P<g0>{pat})")
else:
raise Prevention
- Always use (?P<name>...) for capture groups in str.extract patterns.
- Lint regex patterns used with str.extract to require named groups.
- Reserve str.contains/str.match for boolean matching, not str.extract.
When it happens
Trigger: Calling `s.str.extract(r"(\\d+)")` (unnamed group) or `s.str.extract(r"\\d+")` (no group at all) on a pyarrow-backed string Series. With expand=True (the default) on this backend, every capture must be named.
Common situations: Patterns authored for object/string[python] dtypes where unnamed groups returned numeric columns (0, 1, ...). Copy-pasting regex from another language/tool that uses positional groups. Using str.extract for boolean matching instead of str.contains.
Related errors
- Only flags=0 is implemented.
- Invalid side: {side}. Side must be one of 'left', 'right', '
- invalid normalization form
- replace is not supported with a re.Pattern, callable repl, c
- contains not implemented with {flags=}
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/39a606025cc08c5c.
Report an issue: GitHub.