pola-rs/polars · error

can't convert to Decimal

Error message

can't convert {pyseries.dtype()} to Decimal

What it means

In `sequence_to_pyseries`, when the requested dtype is Decimal, Polars only accepts input sequences whose inferred dtype is Decimal, integer, or Null. Any other inferred dtype (float, string, etc.) cannot be losslessly interpreted as Decimal, so a TypeError is raised.

Solutions

  1. Pass decimal.Decimal values in the sequence instead of float/str: pl.Series([decimal.Decimal('1.5')], dtype=pl.Decimal).
  2. Construct without dtype, then cast explicitly: pl.Series([1.5]).cast(pl.Decimal(scale=2)).
  3. Convert floats to int-scaled values (e.g. cents) and cast with the desired scale.

Example fix

// before
pl.Series([1.5, 2.5], dtype=pl.Decimal)
// after
from decimal import Decimal as D
pl.Series([D('1.5'), D('2.5')], dtype=pl.Decimal)
Defensive patterns

Strategy: type-guard

Validate before calling

if any(not isinstance(v, (decimal.Decimal, int, type(None))) for v in values):
    raise TypeError('Decimal dtype requires Decimal/int values')

Type guard

def decimal_safe(values) -> bool:
    import decimal
    return all(isinstance(v, (decimal.Decimal, int)) or v is None for v in values)

Try / catch

try:
    s = pl.Series(values, dtype=pl.Decimal)
except TypeError as e:
    if "to Decimal" in str(e):
        s = pl.Series([decimal.Decimal(str(v)) for v in values])
    else:
        raise

Prevention

When it happens

Trigger: pl.Series(values, dtype=pl.Decimal) where values are floats or strings, e.g. pl.Series([1.5, 2.5], dtype=pl.Decimal) or pl.Series(['1.5'], dtype=pl.Decimal).

Common situations: Building Decimal columns from money data held as floats; parsing CSV-like lists of numeric strings into Decimal; strict dtype declarations on sequences of Decimal-incompatible Python values.

Related errors


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

Appendix: source

Thrown at py-polars/src/polars/_utils/construction/series.py:191

            if pyseries.dtype() != dtype:
                pyseries = pyseries.cast(dtype, strict=strict, wrap_numerical=False)

        # Uninstanced Decimal is a bit special and has various inference paths
        if dtype == Decimal:
            if pyseries.dtype() == String:
                pyseries = pyseries.str_to_decimal_infer(inference_length=0)
            elif pyseries.dtype().is_float():
                # Go through string so we infer an appropriate scale.
                pyseries = pyseries.cast(
                    String, strict=strict, wrap_numerical=False
                ).str_to_decimal_infer(inference_length=0)
            elif pyseries.dtype().is_integer() or pyseries.dtype() == Null:
                pyseries = pyseries.cast(
                    Decimal(scale=0), strict=strict, wrap_numerical=False
                )
            elif not isinstance(pyseries.dtype(), Decimal):
                msg = f"can't convert {pyseries.dtype()} to Decimal"
                raise TypeError(msg)

        return pyseries

    elif isinstance(dtype, Map):
        # A dict is otherwise inferred as a Struct, so the Map dtype has to drive this.
        return PySeries.new_from_any_values_and_dtype(
            name, values, dtype, strict=strict
        )

    elif dtype == Map:
        msg = "Map requires a key and a value type, e.g. `pl.Map(pl.String, pl.Int64)`"
        raise TypeError(msg)

    elif dtype == Struct:
        # This is very bad. Goes via rows? And needs to do outer nullability separate.
        # It also has two data passes.
        # TODO: eventually go into struct builder
        struct_schema = dtype.to_schema() if isinstance(dtype, Struct) else None

View on GitHub (pinned to fe841f959e)