tursodatabase/turso · error · TursoServerlessException

Unexpected describe response

Error message

Unexpected describe response

What it means

After a describe pipeline round-trip, the client expects the first result to carry a nested response.Result of type describe. When the response shape does not match — no nested result element, or an unrecognized type — it throws 'Unexpected describe response'. This is a protocol-shape mismatch, not a SQL error.

Source

Thrown at bindings/dotnet/src/Turso.Serverless.Client/TursoSession.cs:72

                throw new TursoServerlessException(result.Error?.Message ?? "Describe execution failed", result.Error?.Code);
            }

            if (result.Response is { Type: "describe", Result: { } resultElement })
            {
                var describe = resultElement.Deserialize<HranaDescribeResult>(new JsonSerializerOptions(JsonSerializerDefaults.Web));
                if (describe is not null)
                {
                    return new TursoStatementDescription(
                        parameterNames: describe.Params?.Select(static p => p.Name ?? "").ToArray() ?? [],
                        columns: describe.Cols?.Select(static c => c.Name ?? "").ToArray() ?? [],
                        columnTypes: describe.Cols?.Select(static c => c.Decltype ?? "").ToArray() ?? [],
                        isExplain: describe.IsExplain,
                        isReadonly: describe.IsReadonly);
                }
            }
        }

        throw new TursoServerlessException("Unexpected describe response");
    }

    internal async Task<TursoResultSet> ExecuteAsync(string sql, HranaStatement statement, TimeSpan? queryTimeout, CancellationToken cancellationToken)
    {
        var request = new HranaCursorRequest
        {
            Baton = _baton,
            Batch = new HranaBatch { Steps = [new HranaBatchStep { Statement = statement }] },
        };

        var entries = await RunCursorAsync(request, queryTimeout, cancellationToken).ConfigureAwait(false);

        var columns = new List<string>();
        var columnTypes = new List<string>();
        var rows = new List<TursoRow>();
        var rowsAffected = 0L;
        long? lastInsertRowid = null;
        IReadOnlyList<string>? rowColumns = null;

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Confirm the URL is the database's Hrana endpoint (libsql://...turso.io or its https/wss equivalent), not a dashboard or REST URL
  2. Bypass proxies/gateways temporarily to see if the shape normalizes
  3. Update Turso.Serverless.Client to the latest version to match current server protocol
  4. Log the raw pipeline response body to identify what actually came back
Defensive patterns

Strategy: try-catch

Validate before calling

var parsed = new Uri(opts.Url); // throws early for malformed URLs
if (parsed.Scheme is not ("libsql" or "https" or "wss" or "http" or "ws")) throw new InvalidOperationException($"Unexpected scheme {parsed.Scheme}");

Try / catch

try { var desc = await session.PrepareAsync(sql, ct); } catch (TursoServerlessException ex) when (ex.Message == "Unexpected describe response") { throw new InvalidOperationException($"{opts.Url} is not speaking the Hrana protocol; check the endpoint and client/server versions", ex); }

Prevention

When it happens

Trigger: options.Url pointing at a plain HTTP/JSON endpoint (REST API, health check route, HTML error page) instead of the Hrana endpoint; an intermediate gateway returning a differently-shaped body; a server build whose pipeline response format predates or postdates the client's expectations.

Common situations: Using the database URL from the Turso platform dashboard but with the wrong scheme/path; pointing at a local mock server during testing; corporate proxies injecting responses; major version mismatch between client package and server.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/efde1ac9d9341c00. Report an issue: GitHub.