Skip to content

Raise DB-API errors for transport failures and empty access tokens - #961

Open
aminghadersohi wants to merge 1 commit into
databricks:mainfrom
aminghadersohi:fix-transport-errors-and-empty-token
Open

aminghadersohi wants to merge 1 commit into
databricks:mainfrom
aminghadersohi:fix-transport-errors-and-empty-token

Conversation

@aminghadersohi

Copy link
Copy Markdown

Problems (observed with 4.4.0 and 4.6.0 against a SQL warehouse)

  1. Raw urllib3 errors. When the workspace is unreachable (connection refused, proxy/tunnel failure), ThriftDatabricksClient.make_request re-raises the urllib3 HTTP error of every request except GetOperationStatus unchanged. So connect() and cursor.execute() raise urllib3.exceptions.MaxRetryError, which is not a PEP 249 error. SQLAlchemy therefore does not wrap it in DBAPIError, and callers that handle database errors treat it as an unexpected crash.
  2. Empty token starts a browser login. connect(access_token="") silently drops the empty token (if access_token:) and falls back to the default interactive U2M OAuth flow. That flow binds a callback server on 127.0.0.1:8020–8024 and blocks until a browser redirect arrives, which on a server means indefinitely. Applications that clear a stale token to trigger their own OAuth flow (and expect the No valid authentication settings! error) hang instead.

Change

  1. Non-GetOperationStatus urllib3 HTTP errors take the normal non-retryable error path, so they surface as RequestError (OperationalError) with the usual context. urllib3 has already applied its retry policy by then.
  2. An explicitly passed empty access_token is kept, and get_auth_provider raises RuntimeError("No valid authentication settings! access_token is empty"). Passing no token at all keeps the documented default (databricks-oauth).

Tests

  • New test_make_request_wraps_urllib3_http_error_as_request_error and test_get_python_sql_connector_auth_provider_empty_access_token: both fail on main and pass here.
  • test_thrift_backend.py, test_auth.py, test_client.py, test_retry.py and test_session.py: 285 passed.
  • Both behaviours were also verified live: through a local CONNECT proxy whose tunnels were cut and then refused, and with access_token="".

- ThriftDatabricksClient.make_request re-raised urllib3 HTTP errors of
  every request except GetOperationStatus unchanged, so an unreachable
  workspace (refused connection, proxy/tunnel failure) surfaced from
  connect() and execute() as a raw urllib3 MaxRetryError instead of a
  DB-API error. Report it through the normal non-retryable path as a
  RequestError (OperationalError).
- connect(access_token="") dropped the empty token and fell back to the
  interactive browser OAuth flow, blocking on a local callback server.
  An explicitly empty token now raises 'No valid authentication
  settings!' at once.

Signed-off-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
Copilot AI lite review requested due to automatic review settings September 26, 2026 09:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Empty-token handling remains inconsistent across OAuth and kernel/recovery paths.

Review effort: Lite
Findings: 1 Low severity

Open (1)
What changed in this PR

This pull request improves DB-API transport error handling and prevents explicitly empty access tokens from silently starting OAuth login flows.

Changes:

  • Wraps transport failures as RequestError.
  • Preserves and rejects explicitly empty access tokens.
  • Adds regression tests for both behaviors.
File Summary
tests/​unit/​test_thrift_backend.py Tests transport-error wrapping.
tests/​unit/​test_auth.py Tests empty-token handling.
src/​databricks/​sql/​client.py Preserves explicitly passed tokens.
src/​databricks/​sql/​backend/​thrift_backend.py Routes transport failures through DB-API handling.
src/​databricks/​sql/​auth/​auth.py Rejects empty access tokens.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

import thrift, errno
from databricks.sql.thrift_api.TCLIService.TCLIService import Client
from databricks.sql.exc import RequestError
from databricks.sql.exc import RequestError, RequestError

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants