stablyai/orca · warning · Error

Unsupported file. Pick a PNG, APNG, JPG, GIF, WebP, or SVG.

Error message

Unsupported file. Pick a PNG, APNG, JPG, GIF, WebP, or SVG.

What it means

Thrown by the pet:import handler when classifyFile() returns null, meaning the file extension on the user's pick is not in the allowlist { .png, .apng, .jpg, .jpeg, .gif, .webp, .svg }. The classifier keys purely on lowercased extension — it does not sniff file magic — so a renamed file with an unsupported extension is rejected even if its bytes are a valid image. The dialog filter already restricts to png/jpg/jpeg/gif/webp/svg, so reaching this error implies the user bypassed the filter or picked an apng via a path the filter did not cover.

Source

Thrown at src/main/ipc/pet.ts:193

      properties: ['openFile'],
      // Why: omit `apng` — macOS maps dialog extensions to UTIs, and apng's missing UTI can drop siblings like webp (APNG uses .png anyway).
      filters: [
        {
          name: 'Pet image',
          extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg']
        }
      ]
    }
    const result = senderWindow
      ? await dialog.showOpenDialog(senderWindow, options)
      : await dialog.showOpenDialog(options)
    if (result.canceled || result.filePaths.length === 0) {
      return null
    }
    const src = result.filePaths[0]
    const classified = classifyFile(src)
    if (!classified) {
      throw new Error('Unsupported file. Pick a PNG, APNG, JPG, GIF, WebP, or SVG.')
    }
    let srcStat: Awaited<ReturnType<typeof stat>>
    try {
      srcStat = await stat(src)
    } catch {
      throw new Error('Could not read the selected file.')
    }
    if (!srcStat.isFile()) {
      throw new Error('Selected path is not a file')
    }
    if (srcStat.size > MAX_BYTES) {
      throw new Error(
        `File is too large (${(srcStat.size / (1024 * 1024)).toFixed(1)} MB). Max is ${MAX_BYTES / (1024 * 1024)} MB.`
      )
    }

    const dir = getPetsDir()
    await mkdir(dir, { recursive: true })

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Convert the asset to PNG, APNG, JPG, GIF, WebP, or SVG before importing.
  2. If picking an APNG, ensure the file keeps its .png extension (APNG is a PNG subtype; the dialog and classifier accept .png).
  3. Re-open the native dialog and pick via the 'Pet image' filter rather than a drag/drop from outside.
  4. Do not pre-filter by content-type header alone — the classifier reads the on-disk extension, so the extension must literally match.
Defensive patterns

Strategy: try-catch

Validate before calling

const ALLOWED = new Set(['.png', '.apng', '.jpg', '.jpeg', '.gif', '.webp', '.svg'])
function isSupportedPetExt(filePath: string): boolean {
  const ext = filePath.slice(filePath.lastIndexOf('.')).toLowerCase()
  return ALLOWED.has(ext)
}

if (!isSupportedPetExt(pickedPath)) {
  notify('Use a PNG, APNG, JPG, GIF, WebP, or SVG.')
  return
}

Try / catch

try {
  await ipcRenderer.invoke('pet:import')
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Unsupported file')) {
    notify('Pick a PNG, APNG, JPG, GIF, WebP, or SVG image.')
  } else throw e
}

Prevention

When it happens

Trigger: pet:import received a filePath whose extname().toLowerCase() is absent from IMAGE_FORMATS, e.g. .bmp, .tiff, .heic, .avif, or a file with no extension. On macOS this can occur when APNG is involved because the dialog filter omits 'apng' on purpose (APNG uses .png).

Common situations: User dragged or past-selected a .heic (iPhone export), .bmp, or .avif; user renamed a supported image to .bin; or a platform file-picker returned a path the extension classifier does not recognize.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/06ccf4e0eeea5a92. Report an issue: GitHub.