pola-rs/polars · error · TypeError
"pad_start" expects a `str`, given a {qualified_type_name(fi
Error message
"pad_start" expects a `str`, given a {qualified_type_name(fill_char)!r} What it means
Raised in the Python layer of Expr.str.pad_start before the call reaches the Rust engine: the fill_char argument must be a plain str. Any other type (int, bytes, None, an Expr) is rejected with a TypeError that names the qualified type of the offending value. The engine only accepts a string fill character, so this is a hard precondition on the argument, not a data-dependent runtime error.
Source
Thrown at py-polars/src/polars/expr/string.py:899
--------
>>> df = pl.DataFrame({"a": ["cow", "monkey", "hippopotamus", None]})
>>> df.with_columns(padded=pl.col("a").str.pad_start(8, "*"))
shape: (4, 2)
┌──────────────┬──────────────┐
│ a ┆ padded │
│ --- ┆ --- │
│ str ┆ str │
╞══════════════╪══════════════╡
│ cow ┆ *****cow │
│ monkey ┆ **monkey │
│ hippopotamus ┆ hippopotamus │
│ null ┆ null │
└──────────────┴──────────────┘
"""
length_pyexpr = parse_into_expression(length)
if not isinstance(fill_char, str):
msg = f'"pad_start" expects a `str`, given a {qualified_type_name(fill_char)!r}'
raise TypeError(msg)
return wrap_expr(self._pyexpr.str_pad_start(length_pyexpr, fill_char))
def pad_end(self, length: int | IntoExprColumn, fill_char: str = " ") -> Expr:
"""
Pad the end of the string until it reaches the given length.
.. engine-support:: in-memory, streaming, distributed
Parameters
----------
length
Pad the string until it reaches this length. Strings with length equal to or
greater than this value are returned as-is. Can be int or expression.
fill_char
The character to pad the string with.
See Also
--------View on GitHub (pinned to df599052da)
Solutions
- Pass fill_char as a str, e.g. fill_char='0' or fill_char='*'
- If the value comes from config or data, convert before the call: str(value) or chr(code)
- For zero-padding use .str.zfill(length), which takes no fill_char at all
- A per-row fill character is unsupported; preprocess with map_batches if you truly need it
Example fix
# before
pl.col('id').str.pad_start(8, fill_char=0)
# after
pl.col('id').str.pad_start(8, fill_char='0')
# or, for zeros specifically:
pl.col('id').str.zfill(8) Defensive patterns
Strategy: type-guard
Validate before calling
fill_char = ' '
assert isinstance(fill_char, str), 'fill_char must be str'
expr = pl.col('s').str.pad_start(10, fill_char=fill_char) Type guard
def is_valid_fill_char(x: object) -> bool:
return isinstance(x, str) and len(x) >= 1 Prevention
- Keep literal arguments (fill_char) and expression arguments (length) straight in the string namespace
- Convert config values once at the boundary: str(value) or chr(code)
- Use .str.zfill for zero padding so no fill_char is passed at all
- Let a type checker (mypy/pyright) catch non-str fill_char via the annotated signature
When it happens
Trigger: Calling pl.col('s').str.pad_start(10, fill_char=0), fill_char=None (e.g. an unset config value), fill_char=b'*' (bytes from a network/serialization layer), or passing a column expression as fill_char (only length is an IntoExpr; fill_char is a literal str parameter).
Common situations: Zero-padding IDs and passing the integer 0 instead of the string '0'; bytes values leaking in from JSON/binary protocols; an optional settings dict yielding None; assuming every string-namespace parameter accepts expressions.
Related errors
- "pad_end" expects a `str`, given a {qualified_type_name(fill
- cannot select columns using key of type {qualified_type_name
- cannot select rows using key of type {qualified_type_name(ke
- cannot treat Series of type {s.dtype} as indices
- only 1D NumPy arrays can be treated as indices
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/5596348c7bb9934f.
Report an issue: GitHub.