Skip to content
This repository was archived by the owner on Jun 11, 2025. It is now read-only.
This repository was archived by the owner on Jun 11, 2025. It is now read-only.

Connection Fails with WSServerHandshakeError 505 for Regional URL (*.region.turso.io), but Turso CLI Succeeds #34

@wrtirado

Description

@wrtirado

1. Environment Details:

  • Operating System: macOS (Sequoia 15.4.1)
  • Python Version: 3.11
  • libsql-client Version: 0.3.1
  • sqlalchemy-libsql Version: 0.1.0
  • aiohttp Version: 3.11.18

2. Problem Description:

I am trying to connect to a Turso database from a Python application running in Docker using libsql-client (and sqlalchemy-libsql). The connection consistently fails during the WebSocket handshake phase with an aiohttp.client_exceptions.WSServerHandshakeError: 505, message='Invalid response status'.

Using the official turso CLI (v1.0.9) to connect to the exact same database URL works perfectly fine.

3. Turso Database URL:

  • The exact hostname format provided by Turso that I am using is: chiro-app-wrtirado.aws-us-west-2.turso.io.
  • And the URL format I used in my Python tests (token hidden) is: libsql://chiro-app-wrtirado.aws-us-west-2.turso.io?authToken=[REDACTED_TOKEN]
  • I also tried wss://... explicitly with the same result, as well.
  • SQLAlchemy connection string was: sqlite+libsql://chiro-app-wrtirado.aws-us-west-2.turso.io?authToken=[REDACTED_TOKEN]&secure=true

4. Evidence of Success (Turso CLI):

Connected to chiro-app at libsql://chiro-app-wrtirado.aws-us-west-2.turso.io

Welcome to Turso SQL shell!

Type ".quit" to exit the shell and ".help" to list all available commands.

→  SELECT 1;
1 
1     
→  .tables
→  .quit

5. Evidence of Failure (Python Client):

I have been using this file to test the Turso connection:

# test_turso_connection.py
import os
import libsql_client

# Ensure LIBSQL_AUTH_TOKEN is available as an environment variable
auth_token = os.environ.get("LIBSQL_AUTH_TOKEN")

if not auth_token:
    print("Error: LIBSQL_AUTH_TOKEN environment variable not set.")
    exit(1)

# Using the libsql scheme directly as Turso provides, with authToken in the URL query
# The sqlalchemy-libsql dialect would normally handle the sqlite+libsql part.
# Here we test the underlying client with what it typically expects for a remote server.
turso_db_hostname = "chiro-app-wrtirado.aws-us-west-2.turso.io"
# client_url = f"libsql://{turso_db_hostname}?authToken={auth_token}"
client_url = f"wss://{turso_db_hostname}?authToken={auth_token}"

print(
    f"Attempting to connect to: {client_url} (using libsql_client.create_client_sync)"
)

try:
    # create_client_sync is used because SQLAlchemy operates synchronously
    # and its DBAPI drivers are expected to be synchronous.
    client = libsql_client.create_client_sync(url=client_url)
    print("Client created successfully.")

    # Test with a simple query to ensure the connection is usable
    print("Attempting to execute a simple query (SELECT 1)...")
    rs = client.execute("SELECT 1")

    print(
        f"Query executed successfully. Result rows: {rs.rows}, Column names: {rs.columns}"
    )

    if rs.rows and len(rs.rows) > 0 and rs.rows[0][0] == 1:
        print("Connection and basic query successful!")
    else:
        print(
            "Query executed, but result was not as expected (expected [[1]] or similar)."
        )

except Exception as e:
    print(f"Connection or query failed: {e}")
    print(f"Type of exception: {type(e)}")
    if hasattr(e, "args"):
        print(f"Exception args: {e.args}")
    # If there are nested exceptions, like in the Alembic traceback
    if e.__cause__:
        print(f"Cause: {e.__cause__}")
        print(f"Type of cause: {type(e.__cause__)}")
    if e.__context__:
        print(f"Context: {e.__context__}")
        print(f"Type of context: {type(e.__context__)}")


finally:
    if "client" in locals() and client:
        client.close()
        print("Client closed.")

With containers up and running, I am using the following command: docker-compose exec -e LIBSQL_AUTH_TOKEN="MY_TOKEN" api python test_turso_connection.py, and this is the full traceback result I get:

Will@Williams-MacBook-Pro-2 cursor-chiro-app % docker-compose exec -e LIBSQL_AUTH_TOKEN="REDACTED_TOKEN" api python test_turso_connection.py
Attempting to connect to: wss://chiro-app-wrtirado.aws-us-west-2.turso.io?authToken=REDACTED_TOKEN (using libsql_client.create_client_sync)
Client created successfully.
Attempting to execute a simple query (SELECT 1)...
Connection or query failed: 505, message='Invalid response status', url='wss://chiro-app-wrtirado.aws-us-west-2.turso.io'
Type of exception: <class 'aiohttp.client_exceptions.WSServerHandshakeError'>
Exception args: (RequestInfo(url=URL('wss://chiro-app-wrtirado.aws-us-west-2.turso.io'), method='GET', headers=<CIMultiDictProxy('Host': 'chiro-app-wrtirado.aws-us-west-2.turso.io', 'Upgrade': 'websocket', 'Connection': 'Upgrade', 'Sec-WebSocket-Version': '13', 'Sec-WebSocket-Key': 'TIyIIaSaiBhP8ML1o5nSiw==', 'Sec-WebSocket-Protocol': 'hrana2', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'Python/3.11 aiohttp/3.11.18')>, real_url=URL('wss://chiro-app-wrtirado.aws-us-west-2.turso.io')), ())
Client closed.

6. What I Have Tried:

I confirmed the database is healthy via the Turso dashboard.
I tried both libsql:// and wss:// schemes directly in the test script.
I tried adding &secure=true to the SQLAlchemy URL.

7. Question:

Is this a known issue, particularly with Turso endpoints having regional hostnames (*.region.turso.io), or could it be a bug in libsql-client's interaction with aiohttp for these specific WebSocket connections?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions