tursodatabase/turso · error · TursoException

Remote request failed with HTTP {(int)response.StatusCode} {

Error message

Remote request failed with HTTP {(int)response.StatusCode} {response.ReasonPhrase}: {body}

What it means

TursoRemoteClient.SendAsync wraps every non-success HTTP response in a TursoException that includes the status code, reason phrase, and the full response body. This is the single funnel for all remote-side failures: authentication problems (401/403), unknown database URLs (404), rate limiting (429), and server errors (5xx). Reading the numeric code out of the message is the way to branch on the failure class.

Source

Thrown at bindings/dotnet/src/Turso.Data/TursoRemoteClient.cs:156

        var json = JsonSerializer.Serialize(request, JsonOptions);
        using var content = new StringContent(json, Encoding.UTF8, "application/json");
        using var httpRequest = new HttpRequestMessage(HttpMethod.Post, _pipelineUri)
        {
            Content = content,
        };

        if (_authToken is not null)
            httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _authToken);

        using var response = await _httpClient
            .SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead, effectiveCancellationToken)
            .ConfigureAwait(false);

        var body = await response.Content.ReadAsStringAsync(effectiveCancellationToken).ConfigureAwait(false);
        if (!response.IsSuccessStatusCode)
        {
            throw new TursoException(
                $"Remote request failed with HTTP {(int)response.StatusCode} {response.ReasonPhrase}: {body}");
        }

        try
        {
            return JsonSerializer.Deserialize<RemotePipelineResponse>(body, JsonOptions)
                   ?? throw new TursoException("Remote request returned an empty response.");
        }
        catch (JsonException ex)
        {
            throw new TursoException($"Unable to parse remote response: {ex.Message}");
        }
    }

    private static CancellationTokenSource? CreateTimeout(int commandTimeout, CancellationToken cancellationToken)
    {
        if (commandTimeout <= 0)
            return null;

View on GitHub (pinned to 6c72522679)

Solutions

  1. For 401/403: verify the Auth Token is valid and scoped to the database in the Data Source URL (re-issue with the Turso CLI).
  2. For 404: check the Data Source host matches the database URL shown in the Turso dashboard (watch for typos and stale URLs).
  3. For 429/5xx: retry with exponential backoff and jitter; these classes are transient.
  4. For proxy interference: ensure egress to *.turso.io is direct and the Authorization header survives.

Example fix

// before
var results = await client.ExecuteBatchAsync(batch, 30, true, false, ct);

// after
catch (TursoException ex) when (ex.Message.StartsWith("Remote request failed with HTTP 4"))
{
    // non-retryable: token/URL/config problem — surface it
    logger.LogError(ex, "Remote Turso call rejected");
    throw;
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight sanity (cheap, catches most 401/404 before first query):
if (string.IsNullOrWhiteSpace(options.AuthToken)) throw new ConfigurationException("Turso Auth Token missing");
if (!options.IsRemote) throw new ConfigurationException("Data Source must be a remote URL");

Type guard

static int? ExtractHttpStatus(TursoException ex)
{
    const string prefix = "Remote request failed with HTTP ";
    return ex.Message.StartsWith(prefix) && int.TryParse(ex.Message.AsSpan(prefix.Length, 3), out var code)
        ? code : null;
}

Try / catch

catch (TursoException ex) when (ExtractHttpStatus(ex) is 408 or 429 or >= 500)
{
    await Task.Delay(backoff.Next(), ct); // exponential backoff + jitter, then retry
}
catch (TursoException ex) when (ExtractHttpStatus(ex) is 401 or 403)
{
    logger.LogError(ex, "Turso auth failed — refresh the database token");
    throw;
}

Prevention

When it happens

Trigger: Any remote pipeline request where the server returns non-2xx: an expired or wrong Auth Token (401), a token without access to the database (403), a Data Source URL pointing at a nonexistent database (404), plan limits or burst traffic (429), or Turso Cloud incidents (5xx). Also seen when a proxy or captive portal answers with an unexpected status and HTML body.

Common situations: Rotated/short-lived database tokens not refreshed in long-running services; wrong database URL copied between projects; CI hitting rate limits during parallel test runs; corporate proxies intercepting requests; scheduled token expiry caught only in production.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20). Data as JSON: /api/errors/5aaf2be65b01feb9. Report an issue: GitHub.