{"record":{"id":"c9fb788081aa3bf1","repo":"iOfficeAI/AionUi","slug":"update-errors-downloadnobody","errorCode":"update.errors.downloadNoBody","errorMessage":"update.errors.downloadNoBody","messagePattern":"update\\.errors\\.downloadNoBody","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/desktop/src/process/bridge/updateBridge.ts","lineNumber":535,"sourceCode":"\n  let stream: fs.WriteStream | null = null;\n  try {\n    const res = await fetchWithAllowlistedRedirects(url, abortController.signal);\n\n    if (!res.ok) {\n      throw new Error((await getI18n()).t('update.errors.downloadFailed', { status: res.status }));\n    }\n\n    const contentLengthHeader = res.headers.get('content-length');\n    if (contentLengthHeader) {\n      const parsed = parseInt(contentLengthHeader, 10);\n      if (Number.isFinite(parsed) && parsed > 0) {\n        totalBytes = parsed;\n      }\n    }\n\n    if (!res.body) {\n      throw new Error((await getI18n()).t('update.errors.downloadNoBody'));\n    }\n\n    stream = fs.createWriteStream(file_path);\n    const reader = res.body.getReader();\n\n    let doneReading = false;\n    while (!doneReading) {\n      const { done, value } = await reader.read();\n      doneReading = done;\n      if (doneReading) break;\n      if (!value) continue;\n\n      receivedBytes += value.byteLength;\n\n      const buf = Buffer.from(value);\n      if (!stream.write(buf)) {\n        await new Promise<void>((resolve) => stream?.once('drain', () => resolve()));\n      }","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/iOfficeAI/AionUi/blob/711aa0550ee183ea495dc33e2c05c7943b70a60a/packages/desktop/src/process/bridge/updateBridge.ts#L517-L553","documentation":"Thrown when the update artifact download response has status ok but an empty body (res.body is null). The download cannot proceed because there is nothing to stream to disk.","triggerScenarios":"A 2xx response with Content-Length 0 or a body stream the runtime could not materialize — e.g. a HEAD-like empty response, a redirect chain that ends in an empty 200, or a fetch polyfill/undici quirk returning null body.","commonSituations":"CDN edge returning empty 200 during propagation, misconfigured redirect target, or Node fetch (undici) returning null body for unusual responses (204/empty content-type edge cases).","solutions":["curl -v the artifact URL and inspect status, Content-Length and redirect chain","If a redirect ends in an empty response, fix the allowlisted-redirect target on the CDN","Retry after CDN propagation completes","Check for Node/Electron version-specific undici behaviors with empty bodies if persistent"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const res = await fetch(url);\nif (!res.body || (res.headers.get('content-length') ?? '1') === '0') {\n  // skip streaming; treat as bad artifact and refetch manifest\n}","typeGuard":null,"tryCatchPattern":"catch (err) { if (err.message.includes('downloadNoBody')) { /* re-resolve manifest and retry once */ } throw err; }","preventionTips":["Check Content-Length > 0 before creating the write stream","Treat empty 200s as CDN anomalies and retry","Verify redirect chains end at real artifact content"],"tags":["update","download","empty-body","http"],"backgroundTag":"empty-response-body","analyzedSha":"711aa0550ee183ea495dc33e2c05c7943b70a60a","analyzedAt":"2026-08-28T07:56:06.558Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}