stablyai/orca · warning · Error

Bundle is missing pet.json.

Error message

Bundle is missing pet.json.

What it means

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.

Source

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

      : await dialog.showOpenDialog(options)
    if (result.canceled || result.filePaths.length === 0) {
      return null
    }
    const picked = result.filePaths[0]
    let bundleDir: string
    try {
      const pickedStat = await stat(picked)
      bundleDir = pickedStat.isDirectory() ? picked : dirname(picked)
    } catch {
      throw new Error('Could not read the selected path.')
    }

    const manifestPath = join(bundleDir, 'pet.json')
    let manifestStat: Awaited<ReturnType<typeof stat>>
    try {
      manifestStat = await stat(manifestPath)
    } catch {
      throw new Error('Bundle is missing pet.json.')
    }
    if (!manifestStat.isFile() || manifestStat.size > MAX_MANIFEST_BYTES) {
      throw new Error('pet.json is invalid.')
    }
    if (await isSymlink(manifestPath)) {
      throw new Error('pet.json must not be a symlink.')
    }

    let manifest: ResolvedPetManifest<PetManifest>
    try {
      const raw = await readFile(manifestPath, 'utf8')
      // Why: defend against TOCTOU — the file may have grown between the stat check and this read.
      if (Buffer.byteLength(raw, 'utf8') > MAX_MANIFEST_BYTES) {
        throw new Error('pet.json exceeded the manifest size limit.')
      }
      manifest = applyCodexPetDefaults(PetManifestSchema.parse(JSON.parse(raw)))
    } catch (error) {
      throw new Error(`Invalid pet.json: ${error instanceof Error ? error.message : 'parse error'}`)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Ensure the picked folder contains a pet.json at its top level (not in a subfolder).
  2. If the bundle was extracted from an archive, re-extract preserving the top-level pet.json.
  3. Author a pet.json per the PetManifestSchema (id, displayName, spritesheetPath, optional frame/animations) before importing.
  4. Pick the bundle folder itself, not a nested subfolder.
Defensive patterns

Strategy: validation

Validate before calling

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

async function bundleHasManifest(bundleDir: string): Promise<boolean> {
  try {
    return (await stat(join(bundleDir, 'pet.json'))).isFile()
  } catch {
    return false
  }
}

if (!(await bundleHasManifest(bundleDir))) {
  notify('This folder is missing pet.json — not a valid pet bundle.')
  return
}

Try / catch

try {
  await ipcRenderer.invoke('pet:importPetBundle')
} catch (e) {
  if (e instanceof Error && e.message === 'Bundle is missing pet.json.') {
    notify('That folder has no pet.json. Pick a complete .codex-pet bundle.')
  } else throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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