{"record":{"id":"b0b2c488c185cbaa","repo":"stablyai/orca","slug":"bundle-is-missing-pet-json","errorCode":null,"errorMessage":"Bundle is missing pet.json.","messagePattern":"Bundle is missing pet\\.json\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ipc/pet.ts","lineNumber":262,"sourceCode":"      : await dialog.showOpenDialog(options)\n    if (result.canceled || result.filePaths.length === 0) {\n      return null\n    }\n    const picked = result.filePaths[0]\n    let bundleDir: string\n    try {\n      const pickedStat = await stat(picked)\n      bundleDir = pickedStat.isDirectory() ? picked : dirname(picked)\n    } catch {\n      throw new Error('Could not read the selected path.')\n    }\n\n    const manifestPath = join(bundleDir, 'pet.json')\n    let manifestStat: Awaited<ReturnType<typeof stat>>\n    try {\n      manifestStat = await stat(manifestPath)\n    } catch {\n      throw new Error('Bundle is missing pet.json.')\n    }\n    if (!manifestStat.isFile() || manifestStat.size > MAX_MANIFEST_BYTES) {\n      throw new Error('pet.json is invalid.')\n    }\n    if (await isSymlink(manifestPath)) {\n      throw new Error('pet.json must not be a symlink.')\n    }\n\n    let manifest: ResolvedPetManifest<PetManifest>\n    try {\n      const raw = await readFile(manifestPath, 'utf8')\n      // Why: defend against TOCTOU — the file may have grown between the stat check and this read.\n      if (Buffer.byteLength(raw, 'utf8') > MAX_MANIFEST_BYTES) {\n        throw new Error('pet.json exceeded the manifest size limit.')\n      }\n      manifest = applyCodexPetDefaults(PetManifestSchema.parse(JSON.parse(raw)))\n    } catch (error) {\n      throw new Error(`Invalid pet.json: ${error instanceof Error ? error.message : 'parse error'}`)","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/pet.ts#L244-L280","documentation":"Thrown by the pet:importPetBundle handler when stat(join(bundleDir, 'pet.json')) rejects — the bundle directory exists and was stat'd, but it contains no pet.json at its root. pet.json is the manifest that PetManifestSchema parses (id, displayName, spritesheetPath, frame, animations); without it the bundle cannot be imported.","triggerScenarios":"The picked folder is not a valid .codex-pet bundle (missing manifest), pet.json was renamed/moved/deleted inside the folder, or the user picked a generic folder that merely contains image files.","commonSituations":"User zipped/unzipped a bundle and the manifest was dropped or nested one level deep, the bundle was hand-authored without creating pet.json, or a partial bundle download is missing the manifest.","solutions":["Ensure the picked folder contains a pet.json at its top level (not in a subfolder).","If the bundle was extracted from an archive, re-extract preserving the top-level pet.json.","Author a pet.json per the PetManifestSchema (id, displayName, spritesheetPath, optional frame/animations) before importing.","Pick the bundle folder itself, not a nested subfolder."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { stat } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nasync function bundleHasManifest(bundleDir: string): Promise<boolean> {\n  try {\n    return (await stat(join(bundleDir, 'pet.json'))).isFile()\n  } catch {\n    return false\n  }\n}\n\nif (!(await bundleHasManifest(bundleDir))) {\n  notify('This folder is missing pet.json — not a valid pet bundle.')\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  await ipcRenderer.invoke('pet:importPetBundle')\n} catch (e) {\n  if (e instanceof Error && e.message === 'Bundle is missing pet.json.') {\n    notify('That folder has no pet.json. Pick a complete .codex-pet bundle.')\n  } else throw e\n}","preventionTips":["Ensure pet.json sits at the bundle folder's top level.","Re-extract bundles from archives preserving the top-level manifest.","Pick the bundle folder itself, not a nested subfolder."],"tags":["ipc","pet-overlay","filesystem","bundle-import","manifest"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}