{"record":{"id":"98757503db4e9692","repo":"Wei-Shaw/sub2api","slug":"admin-accounts-grok-noresponsebody","errorCode":null,"errorMessage":"admin.accounts.grok.noResponseBody","messagePattern":"admin\\.accounts\\.grok\\.noResponseBody","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/components/admin/account/AccountTestModal.vue","lineNumber":901,"sourceCode":"    // Use fetch with streaming for SSE since EventSource doesn't support POST\n    const response = await fetch(url, {\n      method: 'POST',\n      headers: {\n        Authorization: `Bearer ${localStorage.getItem('auth_token')}`,\n        'Content-Type': 'application/json',\n        [ADMIN_UI_REQUEST_HEADER]: '1'\n      },\n      body: JSON.stringify(requestBody),\n      signal: abortController.signal\n    })\n\n    if (!response.ok) {\n      throw new Error(`HTTP error! status: ${response.status}`)\n    }\n\n    const reader = response.body?.getReader()\n    if (!reader) {\n      throw new Error(t('admin.accounts.grok.noResponseBody'))\n    }\n\n    const decoder = new TextDecoder()\n    let buffer = ''\n\n    while (true) {\n      const { done, value } = await reader.read()\n      if (done) break\n\n      buffer += decoder.decode(value, { stream: true })\n      const lines = buffer.split('\\n')\n      buffer = lines.pop() || ''\n\n      for (const line of lines) {\n        if (line.startsWith('data: ')) {\n          const jsonStr = line.slice(6).trim()\n          if (jsonStr) {\n            try {","sourceCodeStart":883,"sourceCodeEnd":919,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/frontend/src/components/admin/account/AccountTestModal.vue#L883-L919","documentation":"In frontend/src/components/admin/account/AccountTestModal.vue:901, after response.ok passes, response.body?.getReader() returns undefined when response.body is null, throwing the localized 'admin.accounts.grok.noResponseBody' message. null body occurs when the response genuinely has no payload (204/304, closed stream) or when the browser/proxy environment does not expose fetch streaming.","triggerScenarios":"Admin test endpoint returns an empty or non-streamed response; nginx/CDN buffering collapses the chunked stream into nothing; old WebView without ReadableStream support; server handler returns early with no body on a success status.","commonSituations":"Admin UI behind Cloudflare or an nginx default config that buffers; empty 200 responses from upstream when the model returns nothing; embedded-browser admin panels.","solutions":["Test the endpoint with curl -N to confirm chunked streaming reaches the client.","Set proxy_buffering off / X-Accel-Buffering: no on the admin test route.","Fall back to response.text() when body is missing so non-streamed payloads still render.","Log Content-Type/Content-Length of the failing response to distinguish empty-body from no-stream-support."],"exampleFix":"// before\nconst reader = response.body?.getReader()\nif (!reader) {\n  throw new Error(t('admin.accounts.grok.noResponseBody'))\n}\n\n// after\nconst reader = response.body?.getReader()\nif (!reader) {\n  const text = await response.text().catch(() => '')\n  if (text) { processNonStreamed(text); return }\n  throw new Error(t('admin.accounts.grok.noResponseBody'))\n}","handlingStrategy":"fallback","validationCode":"if (typeof ReadableStream === 'undefined') { showUnsupportedNotice(); }","typeGuard":null,"tryCatchPattern":"try { await runAdminStream(); }\ncatch (e) {\n  if (e.message === t('admin.accounts.grok.noResponseBody')) {\n    await retryOnceWithNoBuffering(); // or fall back to non-stream endpoint\n    return;\n  }\n  throw e;\n}","preventionTips":["Ensure the admin streaming route disables proxy buffering","Fall back to response.text() when getReader() is unavailable","Log response headers of failures to distinguish empty body from no stream support"],"tags":["streaming","admin","proxy","i18n","frontend"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}