You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cursor.close() leaks server-side handle for async commands that were never fetched #791
Cursor.close() does not free the server-side statement handle for async-submitted commands when get_execution_result() was never called. The handle leaks until the session closes (where backend-specific sweeps may or may not catch it).
Repro
importdatabricks.sqlwithdatabricks.sql.connect(...) asconn:
cur=conn.cursor()
cur.execute("SELECT * FROM huge_table", async_op=True)
# User decides not to wait for the result.cur.close()
# Server-side ExecutedAsyncStatement still tracked until conn.close().
Root cause
Cursor.close() at src/databricks/sql/client.py:1713-1718 only nulls active_command_id and closes active_result_set — but for the async-submit-without-fetch case, active_result_set is None, so backend.close_command(active_command_id) is never invoked.
Affects all three backends: Thrift, SEA, and the new kernel backend. Each one tracks the async handle differently (Thrift via Thrift-server-side state; SEA via the SEA statement; kernel via _async_handles dict), but the shared Cursor.close() path doesn't notify any of them about the unfetched async handle.
Suggested fix
Single change in shared Cursor.close():
defclose(self) ->None:
self.open=Falseifself.active_result_set:
self._close_and_clear_active_result_set()
elifself.active_command_idisnotNone:
# async submission that never had get_execution_result called —# the result-set close path didn't fire, so issue an explicit# close_command to free the server-side handle.try:
self.backend.close_command(self.active_command_id)
exceptExceptionasexc:
logger.warning("close_command on cursor close failed: %s", exc)
self.active_command_id=None
Safe across all backends: Thrift's close_command sends TCloseOperation (valid call), SEA's sends a cancel/close, kernel's is already tolerant of unknown ids (no-op).
Surfaced by
Review of PR #787 (kernel backend). Documented as P0 #1 in #787 (comment) — but the leak is pre-existing on Thrift and SEA too, not specific to the kernel backend.
Activity
fix(backend/kernel): address gopalldb's P1 review comments
feat(backend/kernel): add use_kernel=True flag — route through the Ru…
peco-engineer-bot commentedon Jul 17, 2026
🤖 engineer-bot could not complete an automated fix. See the workflow run for details.
peco-engineer-bot commentedon Jul 17, 2026
🤖 engineer-bot could not complete an automated fix. See the workflow run for details.
chore(bots): bump engine pin to 5368de77 (can_use_tool PermissionResu…
peco-engineer-bot commentedon Jul 17, 2026
🤖 engineer-bot could not complete an automated fix. See the workflow run for details.
fix(bots): give the engineer-bot e2e repro a token the env scrub can'…
peco-engineer-bot commentedon Jul 17, 2026
🤖 engineer-bot opened a fix PR: #873
Review before merge.
Cursor.close() leaks server-side handle for async commands that were …
peco-engineer-bot commentedon Jul 23, 2026
🤖 engineer-bot opened a fix PR: #873
Review before merge.