{"record":{"id":"92c784674dd94537","repo":"pola-rs/polars","slug":"unrecognised-connection-type-qualified-type-name-92c784","errorCode":null,"errorMessage":"Unrecognised connection type {qualified_type_name(conn)!r}; no 'execute' or 'cursor' method","messagePattern":"Unrecognised connection type (.+?); no 'execute' or 'cursor' method","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/io/database/_executor.py","lineNumber":472,"sourceCode":"                    return conn\n\n        elif hasattr(conn, \"cursor\"):\n            # connection has a dedicated cursor; prefer over direct execute\n            cursor = (\n                cast(\"Cursor\", cursor()) if callable(cursor := conn.cursor) else cursor\n            )\n            self.can_close_cursor = True\n            return cursor\n\n        elif hasattr(conn, \"execute\"):\n            # can execute directly (given cursor, sqlalchemy connection, etc)\n            return conn\n\n        msg = (\n            f\"Unrecognised connection type {qualified_type_name(conn)!r}; no \"\n            \"'execute' or 'cursor' method\"\n        )\n        raise TypeError(msg)\n\n    async def _sqlalchemy_async_execute(self, query: TextClause, **options: Any) -> Any:\n        \"\"\"Execute a query using an async SQLAlchemy connection.\"\"\"\n        is_session = self._is_alchemy_session(self.cursor)\n        cursor = self.cursor.begin() if is_session else self.cursor  # type: ignore[attr-defined]\n\n        # check if connection is already started (eg: user awaited `engine.connect()`);\n        # if so, use it directly without entering the context manager again\n        if getattr(cursor, \"sync_connection\", None) is not None:\n            return await cursor.execute(query, **options)\n\n        async with cursor as conn:  # type: ignore[union-attr]\n            if is_session and not hasattr(conn, \"execute\"):\n                conn = conn.session\n            result = await conn.execute(query, **options)\n            return result\n\n    def _sqlalchemy_setup(","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/io/database/_executor.py#L454-L490","documentation":"When read_database initializes a cursor from your object (ConnectionExecutor._cursor_init), it accepts anything with a cursor() method (DBAPI connection) or an execute() method (cursor, SQLAlchemy connection, ADBC handle). An object with neither is treated as an unrecognised connection type and raises TypeError including the qualified class name. This is the type-shape gate before any query runs - the repr in the message tells you exactly what leaked in.","triggerScenarios":"pl.read_database('SELECT 1', connection='postgresql://user:pw@host/db') (URI string instead of an object); passing a config dict, an Engine (has neither cursor nor execute), or an ORM Session-like wrapper without execute; passing None.","commonSituations":"Confusing read_database (wants a live connection/cursor object) with read_database_uri (wants a URI string); passing SQLAlchemy create_engine(...) result directly; factory functions returning a wrapper class that hides .execute().","solutions":["For connection strings use pl.read_database_uri(query, uri, engine='connectorx')","For objects, pass a real connection/cursor: engine.connect(), raw DBAPI connect(), or conn.cursor()","If wrapping drivers, expose an execute() method on your wrapper"],"exampleFix":"# before\npl.read_database('SELECT * FROM t', connection='postgresql://user:pw@host/db')\n\n# after - URI goes to read_database_uri\npl.read_database_uri('SELECT * FROM t', 'postgresql://user:pw@host/db')\n\n# after - or pass a live connection object\npl.read_database('SELECT * FROM t', connection=engine.connect())","handlingStrategy":"type-guard","validationCode":"def is_connection_like(obj: object) -> bool:\n    return hasattr(obj, 'cursor') or hasattr(obj, 'execute')\n\nassert is_connection_like(conn), (\n    'read_database needs a connection/cursor object; '\n    'use read_database_uri for connection strings'\n)\ndf = pl.read_database(query, connection=conn)","typeGuard":"from typing import TypeGuard\nfrom typing import Any\n\ndef is_connection_or_cursor(obj: Any) -> TypeGuard[Any]:\n    \"\"\"Narrow to objects polars' read_database can drive.\"\"\"\n    return hasattr(obj, 'cursor') or hasattr(obj, 'execute')","tryCatchPattern":"try:\n    df = pl.read_database(query, connection=conn)\nexcept TypeError as err:\n    if 'Unrecognised connection type' in str(err):\n        df = pl.read_database_uri(query, conn) if isinstance(conn, str) else None\n        if df is None:\n            raise\n    else:\n        raise","preventionTips":["Route connection strings to read_database_uri and live objects to read_database - enforce with a dispatcher helper","Do not pass Engines or Sessions; pass engine.connect() or cursor objects","When wrapping drivers in your own classes, expose execute()"],"tags":["polars","database","connection","typeerror","api-misuse"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}