tursodatabase/turso · error · TursoServerlessException

No cursor response received

Error message

No cursor response received

What it means

On the NDJSON /v3/cursor protocol, the first non-empty line of the 2xx response must deserialize to HranaCursorResponse; remaining lines stream as entries. If the response stream ends with no non-empty line at all, this TursoServerlessException is thrown — the HTTP layer succeeded but delivered no data to parse.

Source

Thrown at bindings/dotnet/src/Turso.Serverless.Client/HranaHttp.cs:92

            }

            var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
            reader = new StreamReader(stream, Encoding.UTF8);

            // The first non-empty line is the cursor response; the rest are cursor entries.
            HranaCursorResponse? cursorResponse = null;
            while (await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false) is { } line)
            {
                if (line.Trim() is not ("" or null) and var trimmed)
                {
                    cursorResponse = JsonSerializer.Deserialize<HranaCursorResponse>(trimmed, JsonOptions);
                    break;
                }
            }

            if (cursorResponse is null)
            {
                throw new TursoServerlessException("No cursor response received");
            }

            var entries = ReadEntriesAsync(response, reader, cancellationToken);
            response = null; // Ownership transferred to the entry enumerator.
            reader = null;
            return (cursorResponse, entries);
        }
        finally
        {
            reader?.Dispose();
            response?.Dispose();
            httpRequest.Dispose();
        }
    }

    private static async IAsyncEnumerable<HranaCursorEntry> ReadEntriesAsync(
        HttpResponseMessage response,
        StreamReader reader,

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Retry the cursor request: an empty stream after successful headers is usually a transient network/infrastructure fault.
  2. Ensure the network path supports unbuffered streaming (test with curl -N against /v3/cursor).
  3. Disable response buffering for this route in your proxy/gateway (nginx proxy_buffering off and equivalents).
  4. Lengthen or remove first-byte read timeouts if intermediaries cut slow-starting streams.
Defensive patterns

Strategy: retry

Validate before calling

// probe that the cursor endpoint streams data before building on it
using var resp = await httpClient.SendAsync(probeRequest, HttpCompletionOption.ResponseHeadersRead);
using var stream = await resp.Content.ReadAsStreamAsync();
using var sr = new StreamReader(stream);
if (await sr.ReadLineAsync() is null) throw new InvalidOperationException("Cursor endpoint returned an empty stream");

Try / catch

catch (TursoServerlessException ex) when (ex.Message == "No cursor response received" && attempt < 3)
{
    await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
    continue; // empty stream after 2xx is almost always transient
}

Prevention

When it happens

Trigger: A 200 response with an entirely empty body; a connection that delivers headers then closes (dropped long-lived/streaming connection); buffering proxies that terminate or truncate streaming responses.

Common situations: Reverse proxies or corporate networks closing streaming connections; intermittent mobile/cloud networking dropping the body; server-side incident producing empty streams; timeouts between headers and first byte.

Related errors


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