janhq/jan · error · Error

response.statusText

Error message

response.statusText

What it means

When importing dragged/dropped audio files via Tauri paths, the app converts the path to an asset URL and fetches it as a blob. A non-ok fetch response throws new Error(response.statusText), surfacing the HTTP failure text. The catch logs 'Failed to read audio file' and skips the file.

Solutions

  1. Add the needed directories to tauri.conf.json assetProtocol.scope (e.g. {"assetProtocol":{"enable":true,"scope":["**"]}}).
  2. Verify the file still exists and is readable before fetching.
  3. Check the browser console/network for the actual HTTP status to identify 403 vs 404.
  4. Upgrade/verify @tauri-apps/api convertFileSrc usage matches the installed Tauri version.

Example fix

// before
const response = await fetch(fileUrl)
if (!response.ok) throw new Error(response.statusText)
// after
const response = await fetch(fileUrl)
if (!response.ok) {
  throw new Error(`Failed to read audio file ${path}: ${response.status} ${response.statusText}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

const exists = await invoke('fs_exists', { path })
if (!exists) throw new Error(`Audio file not found: ${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()
  files.push(new File([blob], fileName, { type: mimeType }))
} catch (error) {
  console.error('Failed to read audio file:', path, error)
  toast.error(`Could not read audio: ${path.split(/[\\/]/).pop()}`)
}

Prevention

When it happens

Trigger: fetch(convertFileSrc(path)) returns 4xx/5xx — e.g. the asset protocol is not allowed for that path, the file was deleted/moved after selection, or the path is outside the Tauri asset scope.

Common situations: Dropping files from directories not whitelisted in Tauri's asset protocol scope; files on network/removable drives that vanished; Tauri security config (assetProtocol enable/scope) missing; permission errors reading the 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/e1810f2736b75485. Report an issue: GitHub.

Appendix: source

Thrown at web-app/src/containers/ChatInput.tsx:1584

    if (textareaRef.current) textareaRef.current.focus()
  }

  const openAudioPicker = useCallback(async () => {
    if (isPlatformTauri()) {
      try {
        const selected = await serviceHub.dialog().open({
          multiple: true,
          filters: [{ name: 'Audio', extensions: ['wav', 'mp3'] }],
        })
        if (selected) {
          const paths = Array.isArray(selected) ? selected : [selected]
          const files: File[] = []
          for (const path of paths) {
            try {
              const { convertFileSrc } = await import('@tauri-apps/api/core')
              const fileUrl = convertFileSrc(path)
              const response = await fetch(fileUrl)
              if (!response.ok) throw new Error(response.statusText)
              const blob = await response.blob()
              const fileName = path.split(/[\\/]/).filter(Boolean).pop() || 'audio'
              const ext = fileName.toLowerCase().split('.').pop()
              const mimeType = ext === 'mp3' ? 'audio/mpeg' : 'audio/wav'
              files.push(new File([blob], fileName, { type: mimeType }))
            } catch (error) {
              console.error('Failed to read audio file:', error)
              toast.error('Failed to read audio file', {
                description: error instanceof Error ? error.message : String(error),
              })
            }
          }
          if (files.length > 0) await processAudioFiles(files)
        }
      } catch (error) {
        console.error('Failed to open audio dialog:', error)
      }
      if (textareaRef.current) textareaRef.current.focus()

View on GitHub (pinned to 7205d770c1)