tursodatabase/turso · error · DatabaseError

No response body

Error message

No response body

What it means

DatabaseError thrown when the fetch Response for /v3/cursor reports ok but has no body to stream — response.body is null/undefined so getReader() cannot be obtained. The cursor protocol streams newline-delimited entries, so a 2xx response without a body cannot be processed and the request fails.

Source

Thrown at serverless/javascript/src/protocol.ts:307

  }

  if (!response.ok) {
    let errorMessage = `HTTP error! status: ${response.status}`;
    try {
      const errorBody = await response.text();
      const errorData = JSON.parse(errorBody);
      if (errorData.message) {
        errorMessage = errorData.message;
      }
    } catch {
      // If we can't parse the error body, use the default HTTP error message
    }
    throw new DatabaseError(errorMessage);
  }

  const reader = response.body?.getReader();
  if (!reader) {
    throw new DatabaseError('No response body');
  }

  const decoder = new TextDecoder();
  let buffer = '';
  let cursorResponse: CursorResponse | undefined;

  // First, read until we get the cursor response (first line)
  try {
    while (!cursorResponse) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });

      const newlineIndex = buffer.indexOf('\n');
      if (newlineIndex !== -1) {
        const line = buffer.slice(0, newlineIndex).trim();
        buffer = buffer.slice(newlineIndex + 1);

View on GitHub (pinned to bad083fafb)

Solutions

  1. Remove or rework middleware that consumes response bodies ahead of the driver
  2. Use a runtime with native streaming fetch (Node 18+/browsers/workers), not old polyfills
  3. Reproduce with curl --raw to confirm the server actually streams a body past your infra

Example fix

// before (test mock with no body — triggers 'No response body')
globalThis.fetch = async () => new Response(null, { status: 200 });

// after (mock that streams NDJSON)
globalThis.fetch = async () => new Response('{"baton":null,"base_url":null}\n', {
  status: 200,
  headers: { "content-type": "application/octet-stream" },
});
Defensive patterns

Strategy: retry

Try / catch

try {
  return await db.all(sql);
} catch (e) {
  if (e instanceof Error && e.message === "No response body") {
    await db.reconnect(); // fresh session, baton already reset
    return await db.all(sql); // one retry
  }
  throw e;
}

Prevention

When it happens

Trigger: A proxy, service worker, or custom fetch returning 2xx with a null body; middleware that consumes the response body before handing the Response to the driver; HTTP 204-style responses from a misrouted endpoint that acknowledges but never streams.

Common situations: Next.js/Cloudflare Workers middleware that reads response bodies for logging; isomorphic-fetch-style polyfills that don't expose streaming bodies; test mocks returning new Response(null, { status: 200 }).

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/ad0bcd5094d4a298. Report an issue: GitHub.