pola-rs/polars · error · ValueError

=" " should be a single byte character or empty, but is…

Error message

{arg_name}="{arg}" should be a single byte character or empty, but is {arg_byte_length} bytes long

What it means

Polars requires CSV delimiter-like arguments (separator, quote_char, etc.) to be exactly one byte, or — only when `can_be_empty=True` — an empty string. `_check_arg_is_1byte` measures the UTF-8 byte length of the argument and raises this ValueError when an empty-allowed argument is longer than one byte. This guards against multi-byte characters passed to the Rust CSV parser, which operates on single-byte tokens.

Solutions

  1. Inspect the argument's byte length: `len(arg.encode("utf-8"))` — it must be 1 (or 0 for empty-allowed args).
  2. Replace multi-character values with the intended single ASCII byte, e.g. `quote_char='"'` or `separator=","`.
  3. For tab separators use the actual tab character `"\t"` (one byte), not a literal "tab" string or two spaces.
  4. If you intended no quote handling, pass an empty string `""` (allowed for `quote_char`).

Example fix

// before
pl.read_csv("data.csv", separator="||")
# after
pl.read_csv("data.csv", separator="|")
Defensive patterns

Strategy: validation

Validate before calling

def check_byte_arg(arg: str, allow_empty: bool = False) -> str:
    n = len(arg.encode("utf-8"))
    if allow_empty and n > 1:
        raise ValueError(f"{arg!r} must be 0 or 1 bytes, got {n}")
    if not allow_empty and n != 1:
        raise ValueError(f"{arg!r} must be exactly 1 byte, got {n}")
    return arg

sep = check_byte_arg(sep, allow_empty=True)

Prevention

When it happens

Trigger: Calling `read_csv`, `scan_csv`, `write_csv`, or `sink_csv` with an argument validated with `can_be_empty=True` (e.g. `quote_char`) that encodes to more than 1 byte — e.g. `quote_char="''"` (two chars) or a multi-byte Unicode character like `"«"`.

Common situations: Copy-pasting a typographic quote or full-width character as a separator; accidentally passing a two-character string like "\t\t" or "||"; confusion between a Python str of one character and one byte for non-ASCII input.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/5edcae7ace82389f. Report an issue: GitHub.

Appendix: source

Thrown at py-polars/src/polars/io/csv/_utils.py:22

if TYPE_CHECKING:
    from collections.abc import Sequence

    from polars import DataFrame


def _check_arg_is_1byte(
    arg_name: str, arg: str | None, *, can_be_empty: bool = False
) -> None:
    if isinstance(arg, str):
        arg_byte_length = len(arg.encode("utf-8"))
        if can_be_empty:
            if arg_byte_length > 1:
                msg = (
                    f'{arg_name}="{arg}" should be a single byte character or empty,'
                    f" but is {arg_byte_length} bytes long"
                )
                raise ValueError(msg)
        elif arg_byte_length != 1:
            msg = (
                f'{arg_name}="{arg}" should be a single byte character, but is'
                f" {arg_byte_length} bytes long"
            )
            raise ValueError(msg)


def _update_columns(df: DataFrame, new_columns: Sequence[str]) -> DataFrame:
    if df.width > len(new_columns):
        cols = df.columns
        for i, name in enumerate(new_columns):
            cols[i] = name
        new_columns = cols
    df.columns = list(new_columns)
    return df

View on GitHub (pinned to fe841f959e)