{"record":{"id":"1aeeb18962faf8ca","repo":"janhq/jan","slug":"failed-to-fetch-file-response-statustext","errorCode":null,"errorMessage":"Failed to fetch file: ${response.statusText}","messagePattern":"Failed to fetch file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web-app/src/containers/ChatInput.tsx","lineNumber":1768,"sourceCode":"              extensions: ['jpg', 'jpeg', 'png'],\n            },\n          ],\n        })\n\n        if (selected) {\n          const paths = Array.isArray(selected) ? selected : [selected]\n          const files: File[] = []\n\n          for (const path of paths) {\n            try {\n              // Use Tauri's convertFileSrc to create a valid URL for the file\n              const { convertFileSrc } = await import('@tauri-apps/api/core')\n              const fileUrl = convertFileSrc(path)\n\n              // Fetch the file as blob\n              const response = await fetch(fileUrl)\n              if (!response.ok) {\n                throw new Error(`Failed to fetch file: ${response.statusText}`)\n              }\n\n              const blob = await response.blob()\n              const fileName =\n                path.split(/[\\\\/]/).filter(Boolean).pop() || 'image'\n              const ext = fileName.toLowerCase().split('.').pop()\n              const mimeType =\n                ext === 'png'\n                  ? 'image/png'\n                  : ext === 'jpg' || ext === 'jpeg'\n                    ? 'image/jpeg'\n                    : 'image/jpeg'\n\n              const file = new File([blob], fileName, { type: mimeType })\n              files.push(file)\n            } catch (error) {\n              console.error('Failed to read file:', error)\n              toast.error('Failed to read file', {","sourceCodeStart":1750,"sourceCodeEnd":1786,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/web-app/src/containers/ChatInput.tsx#L1750-L1786","documentation":"For dragged image files the app fetches them via Tauri's convertFileSrc asset URL; any non-ok response throws 'Failed to fetch file: <statusText>'. This is the image-branch equivalent of the audio/video import fetch guards and feeds the same catch-and-skip flow.","triggerScenarios":"fetch(fileUrl) resolves with !response.ok for a dragged image path — outside asset scope, deleted file, or asset protocol disabled.","commonSituations":"Missing assetProtocol scope entries in tauri.conf.json; dragging from apps that pass virtual/non-filesystem paths; restricted OS permissions on the source file.","solutions":["Enable/extend assetProtocol (enable:true, scope covering user directories) in tauri.conf.json.","Pre-check file existence/permissions before fetch.","Log response.status alongside statusText for diagnosis.","Fall back to reading via a Tauri fs command when the asset protocol fails."],"exampleFix":"// before\nif (!response.ok) {\n  throw new Error(`Failed to fetch file: ${response.statusText}`)\n}\n// after\nif (!response.ok) {\n  throw new Error(`Failed to fetch file ${path}: ${response.status} ${response.statusText}`)\n}","handlingStrategy":"try-catch","validationCode":"const stat = await invoke('fs_stat', { path })\nif (!stat || stat.size === 0) throw new Error(`Image not readable: ${path}`)","typeGuard":"const isOkResponse = (r: Response): r is Response & { ok: true } => r.ok","tryCatchPattern":"try {\n  const response = await fetch(convertFileSrc(path))\n  if (!response.ok) throw new Error(`${response.status} ${response.statusText}`)\n  const blob = await response.blob()\n} catch (error) {\n  console.error('Failed to fetch image file:', path, error)\n  toast.error(`Could not load image: ${fileName}`)\n}","preventionTips":["Enable and scope the Tauri asset protocol for common user directories.","Reject virtual paths (e.g. from drag sources that are not real files) before fetch.","Include status codes and paths in error logs.","Provide fallback file reading via Tauri fs plugin when the asset URL fails."],"tags":["tauri","fetch","file-loading"],"backgroundTag":"http-error-response","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}