stablyai/orca · warning · Error

Selected path is not a file

Error message

Selected path is not a file

What it means

Thrown by the pet:import handler when stat() succeeds but srcStat.isFile() returns false — the picked path stat'd as a directory, FIFO, character/block device, or socket. The dialog uses properties:['openFile'] so this is unusual, but it can occur when the platform picker returns a bundle/package directory or a non-regular file. The check prevents copying a directory tree into the single-file pet slot.

Source

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

    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 })
    const id = randomUUID()
    // Why: keep the original extension in the on-disk name so pet:read can rebuild the Blob MIME without a separate lookup.
    const fileName = `${id}${classified.ext}`
    const dest = join(dir, fileName)
    try {
      await copyFile(src, dest)
    } catch {
      await rm(dest, { force: true }).catch(() => {})
      throw new Error('Could not save the pet.')

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Pick a regular image file, not a folder or bundle.
  2. If you intended to import a multi-file pet bundle (spritesheet + manifest), use pet:importPetBundle instead of pet:import.
  3. On macOS, navigate into the bundle and select the actual image file if you want a single-image pet.
  4. Avoid pointing the picker at /dev nodes or special files.
Defensive patterns

Strategy: try-catch

Validate before calling

import { stat } from 'node:fs/promises'

async function isRegularFile(path: string): Promise<boolean> {
  try {
    return (await stat(path)).isFile()
  } catch {
    return false
  }
}

if (!(await isRegularFile(pickedPath))) {
  notify('Pick a file, not a folder.')
  return
}

Try / catch

try {
  await ipcRenderer.invoke('pet:import')
} catch (e) {
  if (e instanceof Error && e.message === 'Selected path is not a file') {
    notify('That path is a folder or special file. Pick an image file.')
  } else throw e
}

Prevention

When it happens

Trigger: The picked path is a directory (e.g. a .app bundle on macOS whose internal structure stat'd as a directory), a named pipe/FIFO, a device node under /dev, or a socket file.

Common situations: On macOS the user picked inside a .app or other bundle and the dialog returned the bundle directory; on Linux the user pointed at /dev/... or a FIFO; the user manually typed a directory path into a path field backed by the same handler.

Related errors


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