{"record":{"id":"0bc6947dd6f7e988","repo":"danielmiessler/Fabric","slug":"no-response-from-fabric-backend","errorCode":null,"errorMessage":"No response from fabric backend","messagePattern":"No response from fabric backend","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/routes/chat/+server.ts","lineNumber":116,"sourceCode":"    });\n\n    console.log('6. Fabric response:', {\n      status: fabricResponse.status,\n      ok: fabricResponse.ok,\n      statusText: fabricResponse.statusText\n    });\n\n    if (!fabricResponse.ok) {\n      console.error('Error from Fabric API:', {\n        status: fabricResponse.status,\n        statusText: fabricResponse.statusText\n      });\n      throw new Error(`Fabric API error: ${fabricResponse.statusText}`);\n    }\n\n    const stream = fabricResponse.body;\n    if (!stream) {\n      throw new Error('No response from fabric backend');\n    }\n\n    // Create a TransformStream to inspect the data without modifying it\n    const transformStream = new TransformStream({\n      transform(chunk, controller) {\n        const text = new TextDecoder().decode(chunk);\n        if (text.startsWith('data: ')) {\n          try {\n            const data = JSON.parse(text.slice(6));\n            console.log('Stream chunk format:', {\n              type: data.type,\n              format: data.format,\n              contentLength: data.content?.length\n            });\n          } catch (e) {\n            console.log('Failed to parse stream chunk:', text);\n          }\n        }","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/routes/chat/+server.ts#L98-L134","documentation":"Thrown by the /chat endpoint when fabricResponse.ok is true but fabricResponse.body is null/undefined. For a streaming SSE response the body should always be a ReadableStream; a null body with a 200 means the request was made without streaming (e.g. a GET/HEAD-style empty response), the runtime does not expose streaming bodies, or a redirect/204-style response slipped through. It effectively means the proxy cannot pipe Fabric's output to the client.","triggerScenarios":"Fabric backend returning 200 with an empty body (pattern produced no output), a fetch that followed a redirect to a non-streaming response, running under a runtime/adapter where response.body is not implemented, or the request to Fabric missing the streaming headers Fabric expects so it returns an empty 200.","commonSituations":"SvelteKit adapter or preview environment without full streaming support, Fabric version that closed the stream before writing anything, middleware (compression/proxy) that consumed or stripped the body before the handler read it.","solutions":["Check the logged Fabric response object — if status is 200 but body is null, replay the same request with curl against the Fabric port to see whether it actually streams","Ensure the proxied request preserves the streaming method/headers (Accept: text/event-stream) that Fabric requires","Verify the SvelteKit adapter supports streaming responses (node adapter does; some serverless previews do not)","Upgrade/hot-restart the Fabric server if it is returning empty 200s; check its logs for mid-stream aborts"],"exampleFix":"// before\nconst stream = fabricResponse.body;\nif (!stream) {\n  throw new Error('No response from fabric backend');\n}\n\n// after\nconst stream = fabricResponse.body;\nif (!stream) {\n  // Distinguish 'backend returned nothing' from 'streaming unsupported here'\n  const text = await fabricResponse.text().catch(() => '');\n  throw error(502, text\n    ? `Fabric backend returned a non-streaming response: ${text.slice(0, 200)}`\n    : 'No response body from fabric backend');\n}","handlingStrategy":"type-guard","validationCode":"// Confirm streaming is supported in this runtime before proxying\nif (typeof ReadableStream === 'undefined' || !('body' in Response.prototype)) {\n  throw error(500, 'Streaming responses unsupported by this adapter');\n}","typeGuard":"function hasBody(r: Response): r is Response & { body: ReadableStream<Uint8Array> } {\n  return r.ok && r.body instanceof ReadableStream;\n}\n\n// usage\nif (!hasBody(fabricResponse)) {\n  const text = await fabricResponse.text().catch(() => '');\n  throw error(502, text || 'No response from fabric backend');\n}","tryCatchPattern":"try {\n  if (!hasBody(fabricResponse)) throw error(502, 'No response from fabric backend');\n  return new Response(fabricResponse.body.pipeThrough(transformStream), {\n    headers: { 'Content-Type': 'text/event-stream' }\n  });\n} catch (e) {\n  console.error('Fabric streaming failed:', e);\n  throw error(502, 'Fabric stream unavailable');\n}","preventionTips":["Use a runtime/adapter with ReadableStream support for SSE proxying (node adapter, not static/serverless previews)","Pass through Accept: text/event-stream so Fabric actually streams","narrow with an instanceof ReadableStream guard instead of a truthiness check to also catch body-already-consumed cases"],"tags":["streaming","fabric","fetch-api","sveltekit"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}