{"record":{"id":"7ddf5f87a777e0ce","repo":"stablyai/orca","slug":"repo-icons-must-be-png-files","errorCode":null,"errorMessage":"Repo icons must be PNG files.","messagePattern":"Repo icons must be PNG files\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ipc/shell.ts","lineNumber":269,"sourceCode":"    return result.filePaths[0]\n  })\n\n  ipcMain.handle(\n    'shell:pickRepoIconImage',\n    async (): Promise<{ dataUrl: string; fileName: string } | null> => {\n      const result = await dialog.showOpenDialog({\n        properties: ['openFile'],\n        filters: [{ name: 'Repo icon images', extensions: ['png'] }]\n      })\n      if (result.canceled || result.filePaths.length === 0) {\n        return null\n      }\n\n      const filePath = result.filePaths[0]\n      const extension = extname(filePath).toLowerCase()\n      const mimeType = REPO_ICON_IMAGE_MIME_TYPES[extension]\n      if (!mimeType) {\n        throw new Error('Repo icons must be PNG files.')\n      }\n\n      const stats = await stat(filePath)\n      if (stats.size > MAX_REPO_ICON_UPLOAD_BYTES) {\n        throw new Error('Repo icon image must be 256KB or smaller.')\n      }\n\n      const buffer = await readFile(filePath)\n      return {\n        dataUrl: `data:${mimeType};base64,${buffer.toString('base64')}`,\n        fileName: basename(filePath)\n      }\n    }\n  )\n\n  ipcMain.handle('shell:pickAudio', async (): Promise<string | null> => {\n    const result = await dialog.showOpenDialog({\n      properties: ['openFile'],","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/shell.ts#L251-L287","documentation":"Thrown by the shell:pickRepoIcon handler when the chosen file's extension is not in REPO_ICON_IMAGE_MIME_TYPES, which currently contains only '.png' -> 'image/png'. The dialog filter suggests PNG, but the actual file is double-checked by extension to its lowercase MIME; a jpg, gif, webp, or any non-png file is rejected.","triggerScenarios":"User selects a JPG, GIF, WEBP, SVG, or extensionless file in the picker. Even if the OS dialog shows only PNGs, on some platforms the filter is not enforced, so a user can pick another type. The extension lookup fails and the error is thrown before reading the file.","commonSituations":"Users with icons exported as JPG/SVG; renamed files whose content does not match the extension; OS dialog filter bypassed via drag path; users attempting to upload a logo in a non-PNG format.","solutions":["Convert the image to PNG before selecting it (any image editor or 'magick input.jpg output.png').","If SVG is desired, rasterize it to PNG at the intended size first.","In the renderer, filter the dialog strictly to PNG and validate the extension client-side before relying on the result.","Show an inline hint that only PNG is accepted next to the icon picker."],"exampleFix":"// before (user picks icon.jpg)\nawait ipc.invoke('shell:pickRepoIcon')\n\n// after\n// convert first: magick icon.jpg icon.png\nawait ipc.invoke('shell:pickRepoIcon') // now selects icon.png\n\n// renderer-side guard:\nconst result = await ipc.invoke('shell:pickRepoIcon')\n// (handler already enforces; surface its error as 'Please choose a PNG file.')","handlingStrategy":"validation","validationCode":"import { extname } from 'path'\n\nfunction isPngFile(filePath: string): boolean {\n  return extname(filePath).toLowerCase() === '.png'\n}\n\nconst picked = await pickFile()\nif (picked && !isPngFile(picked)) {\n  showError('Repo icons must be PNG files.')\n  return\n}\nawait ipc.invoke('shell:pickRepoIcon')","typeGuard":"import { extname } from 'path'\nfunction isRepoIconPng(filePath: unknown): filePath is string {\n  return typeof filePath === 'string' && extname(filePath).toLowerCase() === '.png'\n}","tryCatchPattern":"try {\n  await ipc.invoke('shell:pickRepoIcon')\n} catch (e) {\n  if (/PNG/.test((e as Error).message)) showError('Please choose a PNG file.')\n  else throw e\n}","preventionTips":["Convert icons to PNG before selection.","Filter the dialog to PNG and re-validate the extension client-side.","Show an 'PNG only' hint next to the icon picker."],"tags":["ipc","shell","repo-icon","validation","file-format"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}