{"record":{"id":"ad0bcd5094d4a298","repo":"tursodatabase/turso","slug":"no-response-body","errorCode":null,"errorMessage":"No response body","messagePattern":"No response body","errorType":"exception","errorClass":"DatabaseError","httpStatus":null,"severity":"error","filePath":"serverless/javascript/src/protocol.ts","lineNumber":307,"sourceCode":"  }\n\n  if (!response.ok) {\n    let errorMessage = `HTTP error! status: ${response.status}`;\n    try {\n      const errorBody = await response.text();\n      const errorData = JSON.parse(errorBody);\n      if (errorData.message) {\n        errorMessage = errorData.message;\n      }\n    } catch {\n      // If we can't parse the error body, use the default HTTP error message\n    }\n    throw new DatabaseError(errorMessage);\n  }\n\n  const reader = response.body?.getReader();\n  if (!reader) {\n    throw new DatabaseError('No response body');\n  }\n\n  const decoder = new TextDecoder();\n  let buffer = '';\n  let cursorResponse: CursorResponse | undefined;\n\n  // First, read until we get the cursor response (first line)\n  try {\n    while (!cursorResponse) {\n      const { done, value } = await reader.read();\n      if (done) break;\n\n      buffer += decoder.decode(value, { stream: true });\n\n      const newlineIndex = buffer.indexOf('\\n');\n      if (newlineIndex !== -1) {\n        const line = buffer.slice(0, newlineIndex).trim();\n        buffer = buffer.slice(newlineIndex + 1);","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/javascript/src/protocol.ts#L289-L325","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 }).","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"],"exampleFix":"// before (test mock with no body — triggers 'No response body')\nglobalThis.fetch = async () => new Response(null, { status: 200 });\n\n// after (mock that streams NDJSON)\nglobalThis.fetch = async () => new Response('{\"baton\":null,\"base_url\":null}\\n', {\n  status: 200,\n  headers: { \"content-type\": \"application/octet-stream\" },\n});","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await db.all(sql);\n} catch (e) {\n  if (e instanceof Error && e.message === \"No response body\") {\n    await db.reconnect(); // fresh session, baton already reset\n    return await db.all(sql); // one retry\n  }\n  throw e;\n}","preventionTips":["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)"],"tags":["http","streaming","network","runtime"],"backgroundTag":"empty-response-body","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}