tursodatabase/turso · error · anyhow::Error

request failed: {status} {text}

Error message

request failed: {status} {text}

What it means

Raised by the test-harness HTTP client in bindings/rust/src/sync.rs when a request to the sync server returns a non-success status. handle_response treats HTTP 400 with a body containing 'already exists' as success (idempotent create); every other failing status becomes this error with the status code and full response body embedded.

Source

Thrown at bindings/rust/src/sync.rs:1127

        );
        assert_eq!(
            Builder::new_remote(":memory:")
                .with_logical_mvcc_pull(false)
                .logical_mvcc_pull,
            Some(false)
        );
    }

    async fn handle_response(resp: reqwest::Response) -> Result<()> {
        let status = resp.status();
        let text = resp.text().await.unwrap_or_default();

        if status == 400 && text.contains("already exists") {
            return Ok(());
        }

        if !status.is_success() {
            return Err(anyhow!("request failed: {status} {text}"));
        }

        Ok(())
    }

    pub struct TursoServer {
        user_url: String,
        db_url: String,
        host: String,
        db_prefix: String,
        server: Option<Child>,
        _sync_dir_created_by_harness: Option<TempDir>,
        client: Client,
    }

    impl TursoServer {
        pub async fn new() -> Result<Self> {
            let client = Client::new();

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Read the status and body in the message: 404 means wrong path, 400 means payload, 500 means a server-side bug to chase in the server log
  2. Check the sync server's stdout/stderr for the panic or error that produced the status
  3. Rebuild both the server binary and the bindings crate from the same commit so routes and payloads match
  4. For transient 5xx, rerun the test; for 4xx, fix the request path or payload

Example fix

// before
let resp = client.post(url).json(&body).send().await?;
handle_response(resp).await?; // opaque: request failed: 500 ...

// after
let resp = client.post(url).json(&body).send().await?;
let status = resp.status();
let text = resp.text().await.unwrap_or_default();
if !status.is_success() && !(status == 400 && text.contains("already exists")) {
    anyhow::bail!("create failed: {status} body: {text}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

let resp = client.get(format!("{user_url}/health")).send().await?;
anyhow::ensure!(resp.status().is_success(), "sync server unhealthy before request");

Try / catch

match handle_response(resp).await {
    Ok(()) => {}
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("500") || msg.contains("503") { /* retry with backoff */ }
        else { return Err(e); }
    }
}

Prevention

When it happens

Trigger: POSTing a create/upload request that fails server-side without 'already exists' in the body; hitting a renamed or removed route (404); auth failure (401/403); malformed JSON payload after a sync-protocol schema change (400 without that phrase); server bug returning 500.

Common situations: Client harness and tursodb sync server built from different commits so routes or payload schemas disagree; server crashed mid-test and a proxy returns an error status; typos in the URL path used by a custom harness.

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@492c4a71cd (2026-08-20). Data as JSON: /api/errors/88ccdbae00076ba2. Report an issue: GitHub.