tursodatabase/turso · error · Error

HTTP request failed: . URL: , Method: , Body size: bytes

Error message

HTTP request failed: ${e instanceof Error ? e.message : String(e)}. URL: ${fullUrl}, Method: ${request.method}, Body size: ${request.body ? request.body.byteLength : 0} bytes

What it means

This is the SDK's wrapper around a failed fetch() for a sync-engine HTTP request: the message embeds the underlying error, the resolved URL, the HTTP method and the body size, and ioProcessor also logs a full '[Turso HTTP] Request failed:' JSON blob to the console. The failing IO item is then poisoned, so the surrounding operation usually dies right after with 'Unexpected status from operation.resume()'. This error is where the real network diagnosis happens.

Solutions

  1. Read the embedded URL and underlying message - they tell you exactly which endpoint and which network failure (DNS, TLS, refused)
  2. Android: confirm <uses-permission android:name="android.permission.INTERNET"/> in AndroidManifest.xml, and use 10.0.2.2 (not localhost) when targeting a dev machine from the emulator
  3. iOS: use https:// endpoints or add an ATS exception for your dev host
  4. Retry the operation with backoff once connectivity returns; on repeated auth-adjacent failures, verify the authToken is valid for that database

Example fix

// before - emulator cannot reach localhost
const db = await connect({ path: 'r.db', url: 'http://localhost:8080' });

// after
import { Platform } from 'react-native';
const host = Platform.OS === 'android' && __DEV__ ? '10.0.2.2' : 'myserver.example.com';
const db = await connect({ path: 'r.db', url: `https://${host}` });
Defensive patterns

Strategy: retry

Validate before calling

// Connectivity pre-flight before sync operations on mobile
export async function isOnline(): Promise<boolean> {
  try {
    const res = await fetch('https://your-db-host/ping', { method: 'HEAD' });
    return res.ok || res.status < 500;
  } catch { return false; }
}

Try / catch

catch (e) { if (e instanceof Error && e.message.startsWith('HTTP request failed:')) { await backoff(++attempt); return db.pull(); // retry with backoff while online } throw e; }

Prevention

When it happens

Trigger: connect()/pull()/push()/sync() (or any query on a partial-sync replica that must fetch missing pages) while fetch() throws: DNS failure, TLS error, connection refused, Android missing the INTERNET permission, iOS ATS blocking a plain-http URL, or an emulator hitting localhost instead of 10.0.2.2.

Common situations: Airplane mode / flaky mobile data during sync; local dev server reached via localhost from the Android emulator (use 10.0.2.2); release Android builds without android.permission.INTERNET; http:// (non-TLS) endpoints rejected by iOS App Transport Security; corporate proxies interfering with libsql://-style endpoints normalized to https://.

Related errors


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

Appendix: source

Thrown at bindings/react-native/src/internal/ioProcessor.ts:217

  let response;
  try {
    response = await fetch(fullUrl, options);
  } catch (e) {
    // Detailed error logging
    const errorDetails = {
      url: fullUrl,
      method: request.method,
      hasBody: !!request.body,
      bodySize: request.body ? request.body.byteLength : 0,
      bodyType: request.body ? Object.prototype.toString.call(options.body) : 'none',
      error: e instanceof Error ? {
        message: e.message,
        name: e.name,
        stack: e.stack,
      } : String(e),
    };
    console.error('[Turso HTTP] Request failed:', JSON.stringify(errorDetails, null, 2));
    throw new Error(`HTTP request failed: ${e instanceof Error ? e.message : String(e)}. URL: ${fullUrl}, Method: ${request.method}, Body size: ${request.body ? request.body.byteLength : 0} bytes`);
  }


  // Set status code
  item.setStatus(response.status);

  // Read response body and push to item
  const responseData = await response.arrayBuffer();
  if (responseData.byteLength > 0) {
    item.pushBuffer(responseData);
  }

  // Mark as done
  item.done();
}

/**
 * Process a full read request (atomic file read)

View on GitHub (pinned to 244cde92a7)