Skip to content

Commit d500207

Browse files
authored
fix: handle closed DuckDB connections gracefully (#7111) (#7114)
Fixes #7111 where closed DuckDB connections would trigger error logging when marimo attempts to query them for database information.
1 parent e32b579 commit d500207

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

marimo/_data/get_datasets.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,15 @@ def execute_duckdb_query(
9898
return duckdb.execute(query).fetchall()
9999

100100
return connection.execute(query).fetchall()
101-
except Exception:
101+
except Exception as e:
102+
if DependencyManager.duckdb.has():
103+
import duckdb
104+
105+
# Connection is closed, return empty result
106+
if isinstance(e, duckdb.ConnectionException):
107+
LOGGER.debug("Skipping query on closed DuckDB connection")
108+
return []
109+
102110
LOGGER.exception("Failed to execute DuckDB query %s", query)
103111
return []
104112

@@ -156,6 +164,14 @@ def _get_databases_from_duckdb_internal(
156164
if DependencyManager.duckdb.has():
157165
import duckdb
158166

167+
# Connection is closed, skip gracefully
168+
if isinstance(e, duckdb.ConnectionException):
169+
LOGGER.debug(
170+
"Skipping closed DuckDB connection for engine %s",
171+
engine_name,
172+
)
173+
return []
174+
159175
# Certain ducklakes don't support SHOW ALL TABLES
160176
if isinstance(e, duckdb.NotImplementedException):
161177
return get_duckdb_databases_agg_query(connection, engine_name)
@@ -424,7 +440,15 @@ def _get_duckdb_database_names(
424440
if not internal:
425441
database_names.append(database_name)
426442
return database_names
427-
except Exception:
443+
except Exception as e:
444+
if DependencyManager.duckdb.has():
445+
import duckdb
446+
447+
# Connection is closed, skip gracefully
448+
if isinstance(e, duckdb.ConnectionException):
449+
LOGGER.debug("Skipping closed DuckDB connection")
450+
return []
451+
428452
LOGGER.debug("Failed to get database names from DuckDB")
429453
return []
430454

tests/_data/test_get_datasets.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,44 @@ def test_get_databases_agg_query() -> None:
571571
]
572572

573573
connection.execute(cleanup_query)
574+
575+
576+
@pytest.mark.skipif(not HAS_DEPS, reason="optional dependencies not installed")
577+
def test_get_databases_with_closed_connection() -> None:
578+
"""Test that closed connections are handled gracefully without errors."""
579+
import duckdb
580+
581+
# Create a connection, add tables, then close it
582+
connection = duckdb.connect(":memory:")
583+
connection.execute("CREATE TABLE test_table (id INTEGER, name VARCHAR)")
584+
connection.close()
585+
586+
# This should not raise an exception
587+
result = get_databases_from_duckdb(
588+
connection=connection, engine_name=VariableName("closed_engine")
589+
)
590+
591+
# Should return empty list for closed connection
592+
assert result == []
593+
594+
595+
@pytest.mark.skipif(not HAS_DEPS, reason="optional dependencies not installed")
596+
def test_get_databases_with_context_manager_closed_connection() -> None:
597+
"""Test that connections closed via context manager are handled gracefully."""
598+
import duckdb
599+
600+
# Use context manager to automatically close connection
601+
with duckdb.connect(":memory:") as connection:
602+
connection.execute(
603+
"CREATE TABLE test_table (id INTEGER, name VARCHAR)"
604+
)
605+
# Store reference to connection
606+
closed_conn = connection
607+
608+
# Connection is now closed, this should not raise an exception
609+
result = get_databases_from_duckdb(
610+
connection=closed_conn, engine_name=VariableName("closed_engine")
611+
)
612+
613+
# Should return empty list for closed connection
614+
assert result == []

0 commit comments

Comments
 (0)