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
- Remove or rework middleware that consumes response bodies ahead of the driver
- Use a runtime with native streaming fetch (Node 18+/browsers/workers), not old polyfills
- 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
- Do not wrap the driver's fetch in middleware that reads response bodies
- Use a runtime with native streaming fetch (Node 18+, browsers, edge workers) — not old polyfills
- Give test mocks real streaming bodies (Response with NDJSON text), not Response(null)
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
- HTTP request failed: ${e instanceof Error ? e.message : Stri
- HTTP error! status: ${response.status}
- No cursor response received
- reader is null
- getAllRows: exceeded ${MAX_IO_RETRIES} IO retries
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/ad0bcd5094d4a298.
Report an issue: GitHub.