pola-rs/polars · error · ValueError

string URI is invalid here; call `read_database_uri` instead

Error message

string URI is invalid here; call `read_database_uri` instead

What it means

Raised by read_database() when the connection argument is a string containing '://', i.e. a URI. read_database expects a live connection/cursor object; URI-based access has a dedicated function, read_database_uri, so polars redirects you instead of trying to interpret the URI as a connection.

Source

Thrown at py-polars/src/polars/io/database/functions.py:256

    ...         query="SELECT * FROM test",
    ...         url="http://localhost:8000",
    ...     )
    ... )  # doctest: +SKIP

    """  # noqa: W505
    if isinstance(connection, str):
        # check for odbc connection string
        if re.search(r"\bdriver\s*=\s*{[^}]+?}", connection, re.IGNORECASE):
            _ = import_optional(
                module_name="arrow_odbc",
                err_prefix="use of ODBC connection string requires the",
                err_suffix="package",
            )
            connection = ODBCCursorProxy(connection)
        elif "://" in connection:
            # otherwise looks like a mistaken call to read_database_uri
            msg = "string URI is invalid here; call `read_database_uri` instead"
            raise ValueError(msg)
        else:
            msg = "unable to identify string connection as valid ODBC (no driver)"
            raise ValueError(msg)

    # adbc_driver_manager must be >= 1.7.0 to support passing Python sequences into
    # parameterised queries (via execute_options) without PyArrow installed
    if (
        execute_options is not None
        and not _PYARROW_AVAILABLE
        and type(connection).__module__.split(".", 1)[0].startswith("adbc")
    ):
        adbc_version_no_pyarrow_required = "1.7.0"
        adbc_driver_manager = import_optional("adbc_driver_manager")
        adbc_str_version = getattr(adbc_driver_manager, "__version__", "0.0")
        if not parse_version(adbc_str_version) >= parse_version(
            adbc_version_no_pyarrow_required
        ):
            msg = (

View on GitHub (pinned to df599052da)

Solutions

  1. Use pl.read_database_uri(query, uri) for string URIs (with engine='connectorx' or 'adbc')
  2. Or keep read_database and pass a real connection object, e.g. sqlalchemy.create_engine(uri).connect()

Example fix

# before
pl.read_database("SELECT * FROM t", "postgresql://user:pw@host/db")

# after
pl.read_database_uri("SELECT * FROM t", "postgresql://user:pw@host/db")
Defensive patterns

Strategy: validation

Validate before calling

def read_any(query: str, conn_or_uri):
    if isinstance(conn_or_uri, str) and "://" in conn_or_uri:
        return pl.read_database_uri(query, conn_or_uri)
    return pl.read_database(query, conn_or_uri)

Type guard

def is_connection_uri(value: object) -> bool:
    return isinstance(value, str) and "://" in value

Prevention

When it happens

Trigger: pl.read_database(query, 'postgresql://user:pass@host/db') — passing a URI string where a connection object is required.

Common situations: Confusing the two database entry points (names differ by only a suffix); porting code between them; copy-pasting a connection string from environment variables into the wrong function.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/0ae3f520d0c5291f. Report an issue: GitHub.