{"record":{"id":"d4af79e27f70e8d6","repo":"flipped-aurora/gin-vue-admin","slug":"llm-request-failed","errorCode":null,"errorMessage":"LLM request failed","messagePattern":"LLM request failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/api/autoCode.js","lineNumber":167,"sourceCode":"    })\n\n    if (!response.ok) {\n      throw await buildFetchError(response)\n    }\n\n    const contentType = String(\n      response.headers.get('content-type') || ''\n    ).toLowerCase()\n    // 上游非 SSE：降级为普通 JSON 解析\n    if (!contentType.includes('text/event-stream') || !response.body) {\n      console.warn(\n        '[SSE] 响应非 SSE 格式，Content-Type:',\n        contentType,\n        '| 降级为普通 JSON 解析'\n      )\n      const body = await parseFetchBody(response)\n      if (typeof body?.code !== 'undefined' && body.code !== 0) {\n        throw new Error(body.msg || 'LLM request failed')\n      }\n      return body\n    }\n    console.debug('[SSE] 已进入流式读取模式')\n\n    const reader = response.body.getReader()\n    const decoder = new TextDecoder()\n    let buffer = ''\n    let done = false\n\n    while (!done) {\n      const result = await reader.read()\n      done = result.done\n      if (done) break\n\n      buffer += decoder.decode(result.value, { stream: true })\n      const lines = buffer.split('\\n')\n      // 保留最后一条可能不完整的行","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/web/src/api/autoCode.js#L149-L185","documentation":"streamLLMRequest first tries to consume the response as an SSE stream; if the Content-Type is not text/event-stream it falls back to normal JSON parsing. If the JSON body has a non-zero code, it throws 'LLM request failed' with the server's msg if present.","triggerScenarios":"The fetch response Content-Type is not SSE, the body parses as JSON with body.code !== 0, and body.msg is empty/undefined so the fallback message is thrown.","commonSituations":"Backend returns a standard {code,msg} error envelope (auth failure, Casbin denial, validation error) instead of an SSE stream; wrong route hit returning JSON; proxy strips the SSE Content-Type.","solutions":["Inspect body.msg from the response to find the real server-side error (often auth or permission)","Confirm the request URL targets the LLM SSE endpoint and the user has API/casbin permission for it","Check server logs at the corresponding handler for the failure reason","Ensure proxies/nginx pass through the text/event-stream Content-Type"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const ct = response.headers.get('Content-Type') || ''\nif (!ct.includes('text/event-stream') && !ct.includes('application/json')) {\n  throw new Error(`Unexpected content-type: ${ct}`)\n}","typeGuard":"function isApiErrorBody(body) {\n  return typeof body?.code !== 'undefined' && body.code !== 0\n}","tryCatchPattern":"try {\n  const body = await streamLLMRequest(url, options)\n} catch (e) {\n  if (e.message === 'LLM request failed') {\n    ElMessage.error('请求被服务端拒绝，请检查登录态与权限')\n  }\n}","preventionTips":["Confirm the user's token/casbin permission before calling the SSE endpoint","Log the response Content-Type and body when falling back to JSON parsing","Keep the {code,msg,data} envelope consistent so msg is always present"],"tags":["sse","http","json","llm","frontend"],"backgroundTag":"api-error-envelope","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}