pola-rs/polars · error · ModuleUpgradeRequiredError

`read_database` queries require at least

Error message

`read_database` queries require at least {module_name} version {minimum_version}

What it means

Raised by `_check_module_version` when the installed database driver module's `__version__` (or `version`) is older than the minimum version polars requires to execute queries through `read_database` for that driver (typically because an Arrow-capable driver API is needed). The driver name and required minimum are included in the message. This is a deliberate gate: older drivers lack APIs polars depends on (e.g. `fetch_arrow_table`/`adbapi` batch behavior).

Solutions

  1. Upgrade the named driver to at least the version in the message, e.g. `pip install -U <module_name>` or `conda update <module_name>`.
  2. If you cannot upgrade, upgrade polars to a version whose minimum matches your driver, or downgrade polars accordingly.
  3. Alternatively pass the result as an already-materialized DataFrame or use `connectorx` URI mode (`read_database_uri`) which bypasses the live-driver query path.
  4. Check for multiple installs/shadowing (`pip show <module_name>`, `python -c "import <module>; print(<module>.__version__)"`) and clean up the environment.

Example fix

// before (requirements.txt)
connectorx==0.2.6
// after (requirements.txt)
connectorx>=0.3.2
Defensive patterns

Strategy: validation

Validate before calling

import importlib.metadata as md
from packaging.version import parse

def check_driver_version(module: str, minimum: str) -> None:
    ver = md.version(module)
    if parse(ver) < parse(minimum):
        raise RuntimeError(f"{module}=={ver} < required {minimum}; run pip install -U {module}")

check_driver_version("connectorx", "0.3.2")

Type guard

def has_min_version(mod: object, minimum: str) -> bool:
    ver = getattr(mod, "__version__", None) or getattr(mod, "version", None)
    try:
        return isinstance(ver, str) and parse_version(ver) >= parse_version(minimum)
    except Exception:
        return False

Try / catch

try:
    df = pl.read_database(query, connection)
except ModuleUpgradeRequiredError as e:
    print(f"Upgrade driver: pip install -U {e}")
    raise

Prevention

When it happens

Trigger: Calling `pl.read_database(query, connection=conn, ...)` with an installed driver module (e.g. connectorx, adbc-driver-* , sqlalchemy, duckdb) whose parsed version is below the driver-specific minimum defined in polars' driver registry, when a query (not an SQLAlchemy-Selectable/instant DataFrame) is passed.

Common situations: Old pin in requirements.txt or conda env predating a driver upgrade; system package manager shipped an outdated driver; user upgraded polars (raising its minimum driver versions) without upgrading drivers.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at py-polars/src/polars/io/database/_executor.py:156

        if self.can_close_cursor and hasattr(self.cursor, "close"):
            from sqlalchemy.ext.asyncio.exc import AsyncContextNotStarted

            with suppress(AsyncContextNotStarted):
                await self.cursor.close()

    @staticmethod
    def _check_module_version(module_name: str, minimum_version: str) -> None:
        """Check the module version against a minimum required version."""
        mod = __import__(module_name)
        with suppress(AttributeError):
            module_version: tuple[int, ...] | None = None
            for version_attr in ("__version__", "version"):
                if isinstance(ver := getattr(mod, version_attr, None), str):
                    module_version = parse_version(ver)
                    break
            if module_version and module_version < parse_version(minimum_version):
                msg = f"`read_database` queries require at least {module_name} version {minimum_version}"
                raise ModuleUpgradeRequiredError(msg)

    def _fetch_arrow(
        self,
        driver_properties: ArrowDriverProperties,
        *,
        batch_size: int | None,
        iter_batches: bool,
    ) -> Iterable[pa.RecordBatch]:
        """Yield Arrow data as a generator of one or more RecordBatches or Tables."""
        fetch_batches = driver_properties["fetch_batches"]
        if not iter_batches or fetch_batches is None:
            fetch_method = driver_properties["fetch_all"]
            res = getattr(self.result, fetch_method)()

            if isinstance(res, Iterable):
                yield from res
            else:
                yield res

View on GitHub (pinned to fe841f959e)