pola-rs/polars · error

unknown physical dtype

Error message

unknown physical dtype

What it means

The Categories.physical property converts the internal physical code (a string like 'u8'/'u16'/'u32') back to a Polars dtype. If the internal value is anything else, the invariant is broken, so a RuntimeError is raised. This normally indicates an internal bug rather than a user error.

Solutions

  1. Reinstall/upgrade py-polars so the Python layer and compiled Rust core match
  2. Avoid constructing Categories objects manually; only use pl.Categorical(...)
  3. If reproducible, file a bug with a minimal reproducer

Example fix

// before (mixed versions)
import polars  # rust core 1.x, python 1.y
// after
pip install --upgrade --force-reinstall polars
Defensive patterns

Strategy: try-catch

Try / catch

try:
    dt = categories.physical
except RuntimeError:
    dt = None  # handle inconsistent state, rebuild Categories

Prevention

When it happens

Trigger: Reading categories.physical on a Categories object whose underlying PyCategories carries an unrecognized physical code — practically only reachable through internal inconsistencies, version mismatch between Rust core and Python bindings, or deserialization of foreign data.

Common situations: Mixed-version py-polars installs where the Rust binary and Python layer disagree; custom/manual construction of Categories objects; corrupted caches.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at py-polars/src/polars/datatypes/classes.py:837

        """The name of this `Categories`."""
        return self._categories.name()

    def namespace(self) -> str:
        """The namespace of this `Categories`."""
        return self._categories.namespace()

    def physical(self) -> PolarsDataType:
        """The physical type used to represent the categories."""
        phys = self._categories.physical()
        if phys == "u8":
            return pldt.UInt8
        elif phys == "u16":
            return pldt.UInt16
        elif phys == "u32":
            return pldt.UInt32
        else:
            msg = "unknown physical dtype"
            raise RuntimeError(msg)

    def is_global(self) -> bool:
        """Returns whether this refers to the global categories."""
        return self._categories.is_global()

    def __getitem__(self, key: str | int) -> str | int:
        if isinstance(key, str):
            if (cat := self._categories.get_cat(key)) is None:
                raise KeyError(key)
            return cat
        elif isinstance(key, int):
            if (s := self._categories.cat_to_str(key)) is None:
                msg = f"category index out of range: {key}"
                raise IndexError(msg)
            return s
        else:
            msg = f"invalid key type {type(key)}; expected str or int"
            raise TypeError(msg)

View on GitHub (pinned to fe841f959e)