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

  1. Enable/extend assetProtocol (enable:true, scope covering user directories) in tauri.conf.json.
  2. Pre-check file existence/permissions before fetch.
  3. Log response.status alongside statusText for diagnosis.
  4. 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

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


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)