tursodatabase/turso · error · DatabaseError
No response body
Error message
No response body
What it means
The fetch to /v3/cursor returned an OK (2xx) status but response.body was null or undefined, so no stream reader could be created. The cursor protocol is a streaming NDJSON body, so an OK response without a body cannot be consumed at all. This is a transport/runtime anomaly, not a SQL or auth problem (those surface as HTTP errors earlier).
Solutions
- Reproduce with curl -i -X POST <url>/v3/cursor ... and confirm the server actually streams a body
- If this happens in tests, fix the fetch stub to include a ReadableStream body (e.g. Response with a stream of NDJSON lines)
- Update @tursodatabase/serverless to the latest patch release in case of runtime compatibility fixes
- Report to Turso if the raw HTTP exchange shows 200-with-empty-body from the server itself
Example fix
// before (test mock without a body)
globalThis.fetch = async () => new Response('', { status: 200 });
// after
const body = new ReadableStream({
start(c) {
c.enqueue(new TextEncoder().encode('{"baton":null,"base_url":null}\n'));
c.close();
},
});
globalThis.fetch = async () => new Response(body, { status: 200 }); Defensive patterns
Strategy: try-catch
Type guard
import { DatabaseError } from '@tursodatabase/serverless';
function isNoBody(e: unknown): e is DatabaseError {
return e instanceof DatabaseError && e.message === 'No response body';
} Try / catch
try {
return await session.execute(sql, args);
} catch (e) {
if (isNoBody(e)) throw new Error('server returned 200 with no body — check fetch polyfill/proxy');
throw e;
} Prevention
- When mocking fetch in tests, always give the Response a ReadableStream body of NDJSON lines
- Verify streaming works through every intermediary (proxies, devtools, service workers) after infrastructure changes
- Keep @tursodatabase/serverless updated alongside runtime upgrades
When it happens
Trigger: A fetch polyfill or test mock that returns a Response without a ReadableStream body; a server or intermediary replying 200 with an genuinely empty body; unusual edge runtimes whose fetch returns a null body for certain response shapes.
Common situations: Unit tests that stub globalThis.fetch with `new Response()` or a plain object lacking body; a misbehaving gateway between the client and the database; upgrading the runtime (Node/workerd version) changes fetch body behavior.
Related errors
- cursor response body ended before the cursor response line
- invalid cursor response
- No cursor response received
- No cursor response received
- reader is null
AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-20).
Data as JSON: /api/errors/ad0bcd5094d4a298.
Report an issue: GitHub.
Appendix: source
Thrown at serverless/javascript/src/protocol.ts:322
}
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 c1e5928725)