tursodatabase/turso · error · ValueError

TursoSyncDialect does not support username/password in URL.

Error message

TursoSyncDialect does not support username/password in URL. Use auth_token query parameter or connect_args instead.

What it means

TursoSyncDialect._validate_sync_url inspects the components SQLAlchemy parsed out of the URL and rejects URLs containing username or password. The sync driver authenticates with a bearer auth_token, not HTTP basic-auth userinfo, so credentials embedded as sqlite+turso_sync://user:pass@/... are a configuration mistake the dialect refuses early with directions to the supported mechanism.

Source

Thrown at bindings/python/turso/sqlalchemy/dialect.py:381

    @classmethod
    def import_dbapi(cls):
        """Import the turso.sync module as DBAPI."""
        import turso.sync

        return turso.sync

    def connect(self, *cargs, **cparams):
        """Remap sync_url to remote_url for libsql-sqlalchemy compatibility."""

        if "sync_url" in cparams and "remote_url" not in cparams:
            cparams["remote_url"] = cparams.pop("sync_url")
        return super().connect(*cargs, **cparams)

    @staticmethod
    def _validate_sync_url(opts: Dict[str, Any]) -> None:
        """Reject URL components that TursoSyncDialect doesn't support."""
        if opts.get("username") or opts.get("password"):
            raise ValueError(
                "TursoSyncDialect does not support username/password in URL. "
                "Use auth_token query parameter or connect_args instead."
            )
        if opts.get("host") or opts.get("port"):
            raise ValueError(
                "TursoSyncDialect does not support host/port in URL. "
                "The local database path goes after ':///', and remote_url "
                "is specified as a query parameter."
            )

    @staticmethod
    def _extract_sync_params(query_params: Dict[str, str]) -> Dict[str, Any]:
        """Extract and convert sync-specific query parameters into kwargs."""
        kwargs: Dict[str, Any] = {}

        auth_token = query_params.pop("auth_token", None)
        if auth_token:
            kwargs["auth_token"] = auth_token

View on GitHub (pinned to bad083fafb)

Solutions

  1. Move the token to the query string: `sqlite+turso_sync:///local.db?auth_token=<token>`
  2. Or pass it out-of-band: `create_engine("sqlite+turso_sync:///local.db", connect_args={"auth_token": token})` — better for secrets, keeps them out of logs
  3. Strip userinfo when generating URLs programmatically

Example fix

# before
engine = create_engine("sqlite+turso_sync://user:secret@/local.db")

# after
engine = create_engine(
    "sqlite+turso_sync:///local.db",
    connect_args={"remote_url": "libsql://db.example.com", "auth_token": "secret"},
)
Defensive patterns

Strategy: validation

Validate before calling

from sqlalchemy.engine import make_url

def lint_turso_sync_url(url: str) -> str:
    u = make_url(url)
    if u.username or u.password:
        raise ValueError(
            "credentials do not belong in the URL; pass auth_token as a query param or connect_args"
        )
    return url

Prevention

When it happens

Trigger: `create_engine("sqlite+turso_sync://user:secret@/local.db")` or any URL copied from a libsql/https endpoint with embedded credentials, then engine.connect() (validation runs in create_connect_args).

Common situations: Porting connection strings from postgres/mysql-style URLs; pasting a libsql:// URL with user:pass into the SQLAlchemy DSN; secret managers templating credentials into the userinfo slot.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/f5889e3a52dc2358. Report an issue: GitHub.