{"record":{"id":"0dc57d2bc8ae8765","repo":"tursodatabase/turso","slug":"sqlite3-row-is-not-supported-as-a-row-factory-on-t","errorCode":null,"errorMessage":"sqlite3.Row is not supported as a row_factory on turso connections; use turso.Row instead","messagePattern":"sqlite3\\.Row is not supported as a row_factory on turso connections; use turso\\.Row instead","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"bindings/python/turso/lib.py","lineNumber":215,"sourceCode":"    \"\"\"\n    Run PyTursoStatement.step() once handling potential async IO loops.\n    \"\"\"\n    while True:\n        status = stmt.step()\n        if status == Status.Io:\n            stmt.run_io()\n            if extra_io:\n                extra_io()\n            continue\n        return status\n\n\ndef _reject_stdlib_row_factory(rf: Any) -> None:\n    stdlib_sqlite3 = sys.modules.get(\"sqlite3\")\n    if stdlib_sqlite3 is None:\n        return\n    if isinstance(rf, type) and issubclass(rf, stdlib_sqlite3.Row):\n        raise TypeError(\"sqlite3.Row is not supported as a row_factory on turso connections; use turso.Row instead\")\n\n\n@dataclass\nclass _Prepared:\n    stmt: PyTursoStatement\n    tail_index: int\n    has_columns: bool\n    column_names: tuple[str, ...]\n\n\n# Connection goes FIRST\nclass Connection:\n    \"\"\"\n    A connection to a Turso (SQLite-compatible) database.\n\n    Similar to sqlite3.Connection with a subset of features focusing on DB-API 2.0.\n    \"\"\"\n","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/python/turso/lib.py#L197-L233","documentation":"pyturso's Connection/Cursor are not subclasses of the stdlib sqlite3 module, so sqlite3.Row cannot wrap turso result rows. When a fetch applies a row_factory that is a subclass of sqlite3.Row, constructing it fails with TypeError, and _reject_stdlib_row_factory replaces that with an explicit message directing you to turso's own Row type (lib.py:917). The error surfaces at fetch time (fetchone/fetchmany/fetchall/iteration), not at assignment time.","triggerScenarios":"`import sqlite3` then `conn.row_factory = sqlite3.Row` on a turso connection (or `cur.row_factory = sqlite3.Row`) followed by any row fetch. Typical when porting sqlite3/aiosqlite code: `for row in cur.execute(\"SELECT ...\")` after setting the factory.","commonSituations":"Migrating an existing sqlite3 project to pyturso; shared helper modules or ORMs that set sqlite3.Row unconditionally; tutorial code copied from the sqlite3 docs; aiosqlite wrappers that inject sqlite3.Row.","solutions":["Use turso's row type instead: `from turso import Row; conn.row_factory = Row` — it provides the same name-based access over turso rows","If you don't need mapping-style access, leave row_factory as None and use index-based tuple access","For shared code supporting both drivers, select the factory conditionally based on the connection type"],"exampleFix":"# before\nimport sqlite3\nconn = turso.connect(\"db\")\nconn.row_factory = sqlite3.Row  # explodes at fetch time\nfor row in conn.execute(\"SELECT id, name FROM t\"):\n    print(row[\"name\"])\n\n# after\nfrom turso import Row\nconn = turso.connect(\"db\")\nconn.row_factory = Row\nfor row in conn.execute(\"SELECT id, name FROM t\"):\n    print(row[\"name\"])","handlingStrategy":"type-guard","validationCode":"import sqlite3\n\ndef pick_row_factory(conn):\n    \"\"\"Return a row factory compatible with the connection's driver.\"\"\"\n    driver = type(conn).__module__\n    if driver.startswith(\"turso\"):\n        from turso import Row\n        return Row\n    return sqlite3.Row\n\nconn.row_factory = pick_row_factory(conn)","typeGuard":"import sqlite3\n\ndef row_factory_supported(rf) -> bool:\n    \"\"\"False when rf is a stdlib sqlite3.Row subclass, which turso rejects.\"\"\"\n    stdlib_row = getattr(sqlite3, \"Row\", None)\n    return not (\n        isinstance(rf, type)\n        and stdlib_row is not None\n        and issubclass(rf, stdlib_row)\n    )","tryCatchPattern":"try:\n    row = cur.fetchone()\nexcept TypeError as e:\n    if \"sqlite3.Row is not supported\" in str(e):\n        conn.row_factory = None  # or turso Row; then re-fetch\n    else:\n        raise","preventionTips":["When porting sqlite3 code, grep for `sqlite3.Row` before switching the import to turso","Centralize row_factory selection in one helper instead of setting it ad hoc","Prefer turso.Row for name-based access; it is the drop-in replacement for sqlite3.Row"],"tags":["python","row-factory","sqlite3-compat","migration"],"backgroundTag":"incompatible-row-factory","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}