janhq/jan · error
Failed to fetch file
Error message
Failed to fetch file: ${response.statusText} What it means
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.
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.
Example fix
// before
if (!response.ok) {
throw new Error(`Failed to fetch file: ${response.statusText}`)
}
// after
if (!response.ok) {
throw new Error(`Failed to fetch file ${path}: ${response.status} ${response.statusText}`)
} Defensive patterns
Strategy: try-catch
Validate before calling
const stat = await invoke('fs_stat', { path })
if (!stat || stat.size === 0) throw new Error(`Image not readable: ${path}`) Type guard
const isOkResponse = (r: Response): r is Response & { ok: true } => r.ok Try / catch
try {
const response = await fetch(convertFileSrc(path))
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`)
const blob = await response.blob()
} catch (error) {
console.error('Failed to fetch image file:', path, error)
toast.error(`Could not load image: ${fileName}`)
} Prevention
- 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.
When it happens
Trigger: fetch(fileUrl) resolves with !response.ok for a dragged image path — outside asset scope, deleted file, or asset protocol disabled.
Common situations: Missing assetProtocol scope entries in tauri.conf.json; dragging from apps that pass virtual/non-filesystem paths; restricted OS permissions on the source file.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- response.statusText
- Cannot connect to at . Please check that the service is…
- Database error
- ${e}
- Failed to decompress archive
AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17).
Data as JSON: /api/errors/1aeeb18962faf8ca.
Report an issue: GitHub.
Appendix: source
Thrown at web-app/src/containers/ChatInput.tsx:1768
extensions: ['jpg', 'jpeg', 'png'],
},
],
})
if (selected) {
const paths = Array.isArray(selected) ? selected : [selected]
const files: File[] = []
for (const path of paths) {
try {
// Use Tauri's convertFileSrc to create a valid URL for the file
const { convertFileSrc } = await import('@tauri-apps/api/core')
const fileUrl = convertFileSrc(path)
// Fetch the file as blob
const response = await fetch(fileUrl)
if (!response.ok) {
throw new Error(`Failed to fetch file: ${response.statusText}`)
}
const blob = await response.blob()
const fileName =
path.split(/[\\/]/).filter(Boolean).pop() || 'image'
const ext = fileName.toLowerCase().split('.').pop()
const mimeType =
ext === 'png'
? 'image/png'
: ext === 'jpg' || ext === 'jpeg'
? 'image/jpeg'
: 'image/jpeg'
const file = new File([blob], fileName, { type: mimeType })
files.push(file)
} catch (error) {
console.error('Failed to read file:', error)
toast.error('Failed to read file', {View on GitHub (pinned to 7205d770c1)