stablyai/orca · error · Error
Animation "${name}" references row ${anim.row} but sheet has
Error message
Animation "${name}" references row ${anim.row} but sheet has ${rows}. What it means
Thrown at pet.ts:349-350 while iterating Object.entries(manifest.animations): if an animation's row index (anim.row) is greater than or equal to the computed rows (sheetHeight / frameHeight). Rows are zero-indexed, so a sheet with 4 rows allows row 0..3.
Source
Thrown at src/main/ipc/pet.ts:350
if (sheetBuf.byteLength > MAX_BYTES) {
throw new Error('Spritesheet exceeded the size limit.')
}
const dims = await readSheetDimensions(sheetBuf)
if (!dims) {
throw new Error('Could not decode the spritesheet image.')
}
const { width: fw, height: fh } = manifest.frame
if (dims.width % fw !== 0 || dims.height % fh !== 0) {
throw new Error(
`Spritesheet ${dims.width}×${dims.height} is not a clean multiple of frame ${fw}×${fh}.`
)
}
const columns = dims.width / fw
const rows = dims.height / fh
if (manifest.animations) {
for (const [name, anim] of Object.entries(manifest.animations)) {
if (anim.row >= rows) {
throw new Error(`Animation "${name}" references row ${anim.row} but sheet has ${rows}.`)
}
if (anim.frames > columns) {
throw new Error(
`Animation "${name}" has ${anim.frames} frames but sheet only has ${columns} columns.`
)
}
if (anim.frameDurationsMs && anim.frameDurationsMs.length !== anim.frames) {
throw new Error(
`Animation "${name}" declares ${anim.frameDurationsMs.length} frame durations but ${anim.frames} frames.`
)
}
}
if (manifest.defaultAnimation && !manifest.animations[manifest.defaultAnimation]) {
throw new Error(`defaultAnimation "${manifest.defaultAnimation}" not in animations.`)
}
}
sprite = {
frameWidth: fw,View on GitHub (pinned to 1136503c6a)
Solutions
- Set the animation's row to a valid zero-based index less than rows (the message states rows).
- If the art needs that row, add rows to the spritesheet so it has enough.
- Re-export the bundle after fixing pet.json.
Example fix
// before — 4-row sheet, animation claims row 4
{ "animations": { "idle": { "row": 4, "frames": 8 } } }
// after — valid zero-based row (0..3)
{ "animations": { "idle": { "row": 3, "frames": 8 } } } Defensive patterns
Strategy: validation
Validate before calling
function validateAnimationsRows(animations: Record<string, {row:number;frames:number}>, rows: number) {
for (const [name, a] of Object.entries(animations)) {
if (a.row >= rows) throw new Error(`animation ${name} row ${a.row} out of range (0..${rows-1})`)
}
} Try / catch
try { await importPetBundle(p) }
catch (e) { if (e instanceof Error && /references row .* but sheet has/.test(e.message)) { /* fix the animation row index */ } else throw e } Prevention
- Remember rows are zero-indexed.
- Re-validate animations whenever you change the sheet height or frame height.
When it happens
Trigger: An animation entry sets row: 5 but the sheet only has 4 rows (rows=4). This runs only when manifest.animations is present (line 347).
Common situations: Author miscounted rows; sheet was trimmed but animations not updated; row indexing confusion (1-based in author's head, 0-based in schema per pet.ts:104 min(0)).
Related errors
- Animation "${name}" has ${anim.frames} frames but sheet only
- Spritesheet ${dims.width}×${dims.height} is not a clean mult
- Animation "${name}" declares ${anim.frameDurationsMs.length}
- defaultAnimation "${manifest.defaultAnimation}" not in anima
- Invalid pet.json: ${error instanceof Error ? error.message :
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/4a74051ae27e3333.
Report an issue: GitHub.