{"record":{"id":"bba9ac879b9f92a5","repo":"jd-opensource/joyagent-jdgenie","slug":"network-response-was-not-ok-bba9ac","errorCode":null,"errorMessage":"Network response was not ok","messagePattern":"Network response was not ok","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/src/components/ActionView/FileList.tsx","lineNumber":114,"sourceCode":"      case 'csv':\n      case 'xlsx':\n        content = <TableRenderer fileUrl={fileItem.url} fileName={fileItem.name} />;\n        break;\n      default:\n        content = <FileRenderer fileUrl={fileItem.url} fileName={fileItem.name} />;\n        break;\n    }\n  }\n\n  const copy = useMemoizedFn(async () => {\n    if (!fileItem?.url) {\n      return;\n    }\n    startCopying();\n    const response = await fetch(fileItem.url);\n    if (!response.ok) {\n      stopCopying();\n      throw new Error('Network response was not ok');\n    }\n    const data = await response.text();\n\n    const copyData = data;\n\n    // const parts = fileItem.name?.split('.');\n    // const suffix = parts[parts.length - 1];\n    // this.activeFileContent = data\n    // const copyData = suffix === 'md' || suffix === 'txt' ? data : `\\`\\`\\`${suffix}\\n${data}\\n\\`\\`\\``;\n    // this.markDownContent = this.md.render(\n    //   suffix === 'md' || suffix === 'txt'\n    //     ? data\n    //     : `\\`\\`\\`${suffix}\\n${data}\\n\\`\\`\\``\n    // )\n    copyText(copyData);\n    stopCopying();\n    showMessage()?.success('复制成功');\n  });","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/jd-opensource/joyagent-jdgenie/blob/2417e0b8b636d941ad5fb14c59b20dddfef5375d/ui/src/components/ActionView/FileList.tsx#L96-L132","documentation":"FileList's copy flow fetches fileItem.url and throws Error('Network response was not ok') on any non-2xx response, stopping the copy operation (stopCopying is called first). The user's copy-file action fails because the source file content could not be downloaded.","triggerScenarios":"Clicking copy on a file whose URL returns 404/403/500; file removed from storage after the list was rendered; expired or revoked download link.","commonSituations":"Stale file list showing deleted entries; permission revoked mid-session; presigned URL expiry between listing and copying.","solutions":["Refresh the file list to drop entries whose files no longer exist","Catch the thrown error around the copy handler and show a user-facing message with retry","Verify/refresh fileItem.url authorization before copying","Check the file service logs for the failing status","Add a HEAD pre-check on the URL before the full copy"],"exampleFix":"// before\nconst response = await fetch(fileItem.url);\nif (!response.ok) {\n  stopCopying();\n  throw new Error('Network response was not ok');\n}\n// after\nconst response = await fetch(fileItem.url);\nif (!response.ok) {\n  stopCopying();\n  message.error(`复制失败：文件下载返回 HTTP ${response.status}`);\n  return;\n}","handlingStrategy":"try-catch","validationCode":"async function canCopy(url: string): Promise<boolean> {\n  try {\n    const res = await fetch(url, { method: 'HEAD' });\n    return res.ok;\n  } catch { return false; }\n}","typeGuard":"function isResponseOk(res: Response): boolean {\n  return res.ok && res.status >= 200 && res.status < 300;\n}","tryCatchPattern":"try {\n  await copyFile(fileItem);\n} catch (e) {\n  stopCopying();\n  message.error(`复制失败：${(e as Error).message}，请刷新文件列表后重试`);\n} finally {\n  stopCopying();\n}","preventionTips":["Always call stopCopying in a finally block so UI state recovers on failure","Refresh the file list before copy operations on stale data","Include response.status in the error message","Re-request download URLs if a copy fails with 403"],"tags":["react","fetch","network","file-copy"],"backgroundTag":"http-error-response","analyzedSha":"2417e0b8b636d941ad5fb14c59b20dddfef5375d","analyzedAt":"2026-09-08T11:28:19.414Z","contentChangedAt":"2026-09-08T11:28:19.414Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}