Skip to content

[Bug]: DuckDB 1.4.0 breaks the package #1344

@Magolor

Description

@Magolor

What happened?

The new DuckDB release changes the interface.

Direct DuckDB connection works:

duckdb.connect(':memory:')

executes successfully

SQLAlchemy + DuckDB engine fails: The error occurs when SQLAlchemy tries to initialize the DuckDB dialect.

TypeError: unhashable type: '_duckdb.typing.DuckDBPyType' in SQLAlchemy's type processing system

Minimal reproduction script:

python -c " import sqlalchemy from sqlalchemy import create_engine try: engine = create_engine('duckdb:///:memory:') conn = engine.connect() result = conn.execute('SELECT 1') print('Basic connection') conn.close() except Exception as e: print(f'Error: {e}') import traceback traceback.print_exc() "

Full Error in log output.

DuckDB Engine Version

0.17.0

DuckDB Version

1.4.0

SQLAlchemy Version

2.0.43

Relevant log output

Error: unhashable type: '_duckdb.typing.DuckDBPyType'
Traceback (most recent call last):
  File "<string>", line 6, in <module>
    conn = engine.connect()
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 3277, in connect
    return self._connection_cls(self)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 143, in __init__
    self._dbapi_connection = engine.raw_connection()
                             ~~~~~~~~~~~~~~~~~~~~~^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 3301, in raw_connection
    return self.pool.connect()
           ~~~~~~~~~~~~~~~~~^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/pool/impl.py", line 445, in connect
    return _ConnectionFairy._checkout(self, self._fairy)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/pool/base.py", line 1264, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/pool/base.py", line 711, in checkout
    rec = pool._do_get()
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/pool/impl.py", line 427, in _do_get
    c = self._create_connection()
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/pool/base.py", line 388, in _create_connection
    return _ConnectionRecord(self)
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/pool/base.py", line 673, in __init__
    self.__connect()
    ~~~~~~~~~~~~~~^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/pool/base.py", line 913, in __connect
    )._exec_w_sync_on_first_run(self.dbapi_connection, self)
      ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/event/attr.py", line 483, in _exec_w_sync_on_first_run
    self(*args, **kw)
    ~~~~^^^^^^^^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/event/attr.py", line 497, in __call__
    fn(*args, **kw)
    ~~^^^^^^^^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/util/langhelpers.py", line 1997, in go
    return once_fn(*arg, **kw)
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/create.py", line 767, in first_connect
    dialect.initialize(c)
    ~~~~~~~~~~~~~~~~~~^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/duckdb_engine/__init__.py", line 523, in initialize
    DefaultDialect.initialize(self, connection)
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/default.py", line 533, in initialize
    self.default_schema_name = self._get_default_schema_name(
                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        connection
        ^^^^^^^^^^
    )
    ^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/dialects/postgresql/base.py", line 3437, in _get_default_schema_name
    return connection.exec_driver_sql("select current_schema()").scalar()
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1779, in exec_driver_sql
    ret = self._execute_context(
        dialect,
    ...<5 lines>...
        distilled_parameters,
    )
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context
    return self._exec_single_context(
           ~~~~~~~~~~~~~~~~~~~~~~~~~^
        dialect, context, statement, parameters
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context
    self._handle_dbapi_exception(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        e, str_statement, effective_parameters, cursor, context
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 2358, in _handle_dbapi_exception
    raise exc_info[1].with_traceback(exc_info[2])
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/base.py", line 1983, in _exec_single_context
    result = context._setup_result_proxy()
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/default.py", line 1853, in _setup_result_proxy
    result = self._setup_dml_or_text_result()
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/default.py", line 1967, in _setup_dml_or_text_result
    result: _cursor.CursorResult[Any] = _cursor.CursorResult(
                                        ~~~~~~~~~~~~~~~~~~~~^
        self, strategy, cursor_description
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/cursor.py", line 1447, in __init__
    metadata = self._init_metadata(context, cursor_description)
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/cursor.py", line 1528, in _init_metadata
    self._metadata = metadata = CursorResultMetaData(
                                ~~~~~~~~~~~~~~~~~~~~^
        self, cursor_description
        ^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/cursor.py", line 376, in __init__
    raw = self._merge_cursor_description(
        context,
    ...<6 lines>...
        loose_column_name_matching,
    )
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/cursor.py", line 633, in _merge_cursor_description
    context.get_result_processor(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        mapped_type, cursor_colname, coltype
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ),
    ^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/engine/default.py", line 1804, in get_result_processor
    return type_._cached_result_processor(self.dialect, coltype)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/<username>/miniconda3/envs/<conda_env_name>/lib/python3.13/site-packages/sqlalchemy/sql/type_api.py", line 951, in _cached_result_processor
    d["result"][coltype] = rp
    ~~~~~~~~~~~^^^^^^^^^
TypeError: unhashable type: '_duckdb.typing.DuckDBPyType'

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions