pandas-dev/pandas · error · ValueError

empty separator

Error message

empty separator

What it means

Raised by the pyarrow-backed string mixin's `_str_partition_expand` when the `sep` argument is empty/falsy. pandas intentionally re-raises pyarrow's 'Empty separator' using the wording Python's built-in `str.partition` uses ('empty separator') so every string dtype (object, StringDtype, ArrowDtype[str]) raises identically. It is a `ValueError`. The guard runs before any pyarrow compute call, so no partial work is done.

Source

Thrown at pandas/core/arrays/_arrow_string_mixins.py:510

        result = result.cast(pa.int64())
        return self._convert_int_result(result)

    def _str_partition_expand(self, sep: str) -> pa.ChunkedArray:
        """
        Split each string on the first occurrence of ``sep``.

        Returns a ``list<string>`` array holding one three-element list per row
        -- the part before the separator, the separator, and the part after --
        which ``StringMethods._wrap_result`` expands into three columns. Rows
        without ``sep`` get two empty strings, matching ``str.partition``.

        The caller wraps this in an :class:`ArrowExtensionArray`; the rows are
        lists, so it is not of the calling array's own type.
        """
        if not sep:
            # pyarrow reports this as "Empty separator"; keep str.partition's
            #  wording so every dtype raises the same way
            raise ValueError("empty separator")

        str_type = self._pa_array.type
        chunks = [
            self._partition_chunk(chunk, sep, str_type)
            for chunk in self._pa_array.chunks
        ]
        return pa.chunked_array(chunks, type=pa.list_(str_type))

    @staticmethod
    def _partition_chunk(chunk: pa.Array, sep: str, str_type: pa.DataType) -> pa.Array:
        """
        Build the ``list<string>`` rows for one chunk of :meth:`_str_partition_expand`.

        Working a chunk at a time keeps the concatenation below within the
        offset width of ``str_type``, which matters for columns near the 2 GiB
        limit of 32-bit ``string``.
        """
        # max_splits=1 gives [before] when sep is absent, else [before, after];

View on GitHub (pinned to 3b7651241d)

Solutions

  1. Pass a non-empty separator string to `Series.str.partition` / `Series.str.rpartition`.
  2. If the separator comes from user input or config, validate `if not sep: raise ValueError(...)` before calling and surface a clearer message.
  3. Handle the empty-separator case explicitly in your code (e.g. return the original string in column 0 and empty strings in columns 1-2) rather than relying on the library.

Example fix

// before
s.str.partition(sep=user_sep)   # user_sep == '' -> ValueError

// after
if not user_sep:
    raise ValueError('separator must be non-empty')
s.str.partition(sep=user_sep)
Defensive patterns

Strategy: validation

Validate before calling

if not sep:
    raise ValueError('separator must be a non-empty string')
s.str.partition(sep=sep)

Type guard

def is_nonempty_str(s: object) -> bool:
    return isinstance(s, str) and len(s) > 0

Try / catch

try:
    parts = s.str.partition(sep)
except ValueError as e:
    if 'empty separator' in str(e):
        raise ValueError('Provide a non-empty separator') from e
    raise

Prevention

When it happens

Trigger: Calling `Series.str.partition('')` or `Series.str.rpartition('')` on a Series whose dtype is `string[pyarrow]` (ArrowExtensionArray of strings). Also reachable via `.str.partition(sep='')` where `sep` resolves to an empty string at runtime, e.g. `sep=some_var or ''`.

Common situations: Passing a user-supplied separator that was not validated; using a default of `''` instead of `None`; migrating from object dtype to `string[pyarrow]` and discovering the empty-sep path now goes through this mixin.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/416de25fbc509293. Report an issue: GitHub.