{"record":{"id":"3d09d740884a70d2","repo":"danielmiessler/Fabric","slug":"fabric-api-error-fabricresponse-statustext","errorCode":null,"errorMessage":"Fabric API error: ${fabricResponse.statusText}","messagePattern":"Fabric API error: (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/routes/chat/+server.ts","lineNumber":111,"sourceCode":"      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify(body)\n    });\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","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/routes/chat/+server.ts#L93-L129","documentation":"Thrown by the SvelteKit /chat server endpoint when it proxies the request to the local Fabric backend and fabricResponse.ok is false. The Fabric REST service (fabric --serve) returned a 4xx/5xx; common causes are an unknown pattern name, missing/invalid API key for the configured vendor, an unreachable or misconfigured model, or the server rejecting the request payload. The thrown message only carries statusText, which hides the backend's error body.","triggerScenarios":"POST /chat with a pattern the backend does not have (404), vendor API key missing/expired (401/500 from Fabric), model name not available to the vendor (400), Fabric server on a different port or an older version with different routes (404), or payload fields the server rejects (422).","commonSituations":"Fabric config (~/.config/fabric/.env) missing OPENAI/ANTHROPIC keys, pattern renamed or removed from the patterns dir, Fabric CLI updated with breaking API changes while the web UI was not, env vars not loaded into the process serving the endpoint.","solutions":["Read the Fabric server's own logs/console output for the matching request — the endpoint already logs status and statusText just above the throw","Verify the vendor API keys exist in Fabric's .env and that the selected model is valid for that vendor","Confirm the pattern name sent in the request exists (fabric --listpatterns / patterns dir) and matches exactly","Check the FABRIC backend URL/port the endpoint targets and that the running fabric --serve version matches what the UI expects","Forward the backend error body instead of statusText so the UI shows the real reason"],"exampleFix":"// before\nif (!fabricResponse.ok) {\n  console.error('Error from Fabric API:', { status: fabricResponse.status, statusText: fabricResponse.statusText });\n  throw new Error(`Fabric API error: ${fabricResponse.statusText}`);\n}\n\n// after\nif (!fabricResponse.ok) {\n  const errBody = await fabricResponse.text().catch(() => '');\n  console.error('Error from Fabric API:', { status: fabricResponse.status, statusText: fabricResponse.statusText, body: errBody });\n  throw error(fabricResponse.status, `Fabric API error: ${errBody || fabricResponse.statusText}`);\n}","handlingStrategy":"try-catch","validationCode":"// Sanity-check the request before proxying\nif (!pattern) throw error(400, 'Missing pattern');\nconst fabricBase = env.FABRIC_URL ?? 'http://localhost:8080';\n// Optional liveness probe before the real call\nconst health = await fetch(`${fabricBase}/health`, { signal: AbortSignal.timeout(2000) }).catch(() => null);\nif (!health?.ok) throw error(502, 'Fabric backend unreachable');","typeGuard":null,"tryCatchPattern":"try {\n  const fabricResponse = await fetch(fabricUrl, { ...init });\n  if (!fabricResponse.ok) {\n    const errBody = await fabricResponse.text().catch(() => '');\n    throw error(fabricResponse.status, `Fabric API error: ${errBody || fabricResponse.statusText}`);\n  }\n  // ... stream\n} catch (e) {\n  if (e && typeof e === 'object' && 'status' in e) throw e; // sveltekit HttpError passthrough\n  throw error(502, `Fabric backend request failed: ${String(e)}`);\n}","preventionTips":["Surface the Fabric error body, not just statusText — statusText is empty under HTTP/2","Keep fabric CLI and web UI versions in lockstep; breaking changes usually appear as 404s on routes","Verify vendor API keys are configured in fabric's .env before selecting that vendor in the UI","Confirm the pattern exists (fabric --listpatterns) when adding dynamic pattern selection"],"tags":["network","http","fabric","proxy","llm"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}