{"record":{"id":"211bf0582665cdfc","repo":"tursodatabase/turso","slug":"no-cursor-response-received","errorCode":null,"errorMessage":"No cursor response received","messagePattern":"No cursor response received","errorType":"exception","errorClass":"DatabaseError","httpStatus":null,"severity":"error","filePath":"serverless/javascript/src/protocol.ts","lineNumber":340,"sourceCode":"      const newlineIndex = buffer.indexOf('\\n');\n      if (newlineIndex !== -1) {\n        const line = buffer.slice(0, newlineIndex).trim();\n        buffer = buffer.slice(newlineIndex + 1);\n\n        if (line) {\n          cursorResponse = JSON.parse(line);\n          break;\n        }\n      }\n    }\n  } catch (error) {\n    reader.releaseLock();\n    wrapAbortError(error);\n  }\n\n  if (!cursorResponse) {\n    reader.releaseLock();\n    throw new DatabaseError('No cursor response received');\n  }\n\n  async function* parseEntries(): AsyncGenerator<CursorEntry> {\n    try {\n      // Process any remaining data in the buffer\n      let newlineIndex;\n      while ((newlineIndex = buffer.indexOf('\\n')) !== -1) {\n        const line = buffer.slice(0, newlineIndex).trim();\n        buffer = buffer.slice(newlineIndex + 1);\n\n        if (line) {\n          yield JSON.parse(line) as CursorEntry;\n        }\n      }\n\n      // Continue reading from the stream\n      while (true) {\n        let readResult: ReadableStreamReadResult<Uint8Array>;","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/javascript/src/protocol.ts#L322-L358","documentation":"DatabaseError thrown when the /v3/cursor response body stream ends (or yields no newline-terminated line) before the first line — the CursorResponse JSON that carries the baton — arrives. The session cannot continue without that baton, so the request fails and the session resets its baton to null for a clean retry.","triggerScenarios":"A proxy or load balancer closing or truncating the chunked response before the first line; response buffering that splits the stream; the server crashing after sending headers but before the first data chunk; a first chunk containing no complete line.","commonSituations":"CDN/nginx buffering or response-size limits cutting chunked responses; API gateways with aggressive response timeouts; local dev proxies that don't forward chunked transfer encoding; platform incidents that kill in-flight streams.","solutions":["Bypass or reconfigure proxies/CDNs in front of the database (disable response buffering, raise stream limits)","Check gateway limits — response timeout and max response size — against long-running query streams","Retry the query: this is usually transient and the session baton was already reset, so the next request starts clean"],"exampleFix":"# before — nginx buffers and can cut the chunked cursor stream\nproxy_buffering on;\n\n# after — pass streaming responses straight through\nlocation /v3/ {\n    proxy_buffering off;\n    proxy_read_timeout 300s;\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await db.all(sql);\n} catch (e) {\n  if (e instanceof Error && e.message === \"No cursor response received\") {\n    await new Promise((r) => setTimeout(r, 200));\n    await db.all(sql); // stream was cut; session baton was reset, retry is safe\n  } else throw e;\n}","preventionTips":["Disable response buffering on any proxy in front of the database","Connect directly to the database URL where possible instead of through gateways","Watch gateway response timeouts — they silently cut long streams"],"tags":["streaming","network","protocol","proxy"],"backgroundTag":"truncated-stream-response","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}