{"record":{"id":"c634c50e61450cb1","repo":"stablyai/orca","slug":"selected-path-is-not-a-file","errorCode":null,"errorMessage":"Selected path is not a file","messagePattern":"Selected path is not a file","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ipc/pet.ts","lineNumber":202,"sourceCode":"    const result = senderWindow\n      ? await dialog.showOpenDialog(senderWindow, options)\n      : await dialog.showOpenDialog(options)\n    if (result.canceled || result.filePaths.length === 0) {\n      return null\n    }\n    const src = result.filePaths[0]\n    const classified = classifyFile(src)\n    if (!classified) {\n      throw new Error('Unsupported file. Pick a PNG, APNG, JPG, GIF, WebP, or SVG.')\n    }\n    let srcStat: Awaited<ReturnType<typeof stat>>\n    try {\n      srcStat = await stat(src)\n    } catch {\n      throw new Error('Could not read the selected file.')\n    }\n    if (!srcStat.isFile()) {\n      throw new Error('Selected path is not a file')\n    }\n    if (srcStat.size > MAX_BYTES) {\n      throw new Error(\n        `File is too large (${(srcStat.size / (1024 * 1024)).toFixed(1)} MB). Max is ${MAX_BYTES / (1024 * 1024)} MB.`\n      )\n    }\n\n    const dir = getPetsDir()\n    await mkdir(dir, { recursive: true })\n    const id = randomUUID()\n    // Why: keep the original extension in the on-disk name so pet:read can rebuild the Blob MIME without a separate lookup.\n    const fileName = `${id}${classified.ext}`\n    const dest = join(dir, fileName)\n    try {\n      await copyFile(src, dest)\n    } catch {\n      await rm(dest, { force: true }).catch(() => {})\n      throw new Error('Could not save the pet.')","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/pet.ts#L184-L220","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pick a regular image file, not a folder or bundle.","If you intended to import a multi-file pet bundle (spritesheet + manifest), use pet:importPetBundle instead of pet:import.","On macOS, navigate into the bundle and select the actual image file if you want a single-image pet.","Avoid pointing the picker at /dev nodes or special files."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { stat } from 'node:fs/promises'\n\nasync function isRegularFile(path: string): Promise<boolean> {\n  try {\n    return (await stat(path)).isFile()\n  } catch {\n    return false\n  }\n}\n\nif (!(await isRegularFile(pickedPath))) {\n  notify('Pick a file, not a folder.')\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  await ipcRenderer.invoke('pet:import')\n} catch (e) {\n  if (e instanceof Error && e.message === 'Selected path is not a file') {\n    notify('That path is a folder or special file. Pick an image file.')\n  } else throw e\n}","preventionTips":["For a multi-file bundle, use pet:importPetBundle instead of pet:import.","On macOS, navigate into a .app bundle to select the actual image.","Avoid pointing the picker at /dev nodes or FIFOs."],"tags":["ipc","pet-overlay","filesystem","electron-dialog","asset-import"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}