stablyai/orca · error · Error
Animation "${name}" has ${anim.frames} frames but sheet only
Error message
Animation "${name}" has ${anim.frames} frames but sheet only has ${columns} columns. What it means
Thrown at pet.ts:352-355 when an animation declares more frames (anim.frames) than the sheet has columns (sheetWidth / frameWidth). Columns are zero-based count, so a sheet with 8 columns supports up to 8 frames per animation row.
Source
Thrown at src/main/ipc/pet.ts:353
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,
frameHeight: fh,
columns,
rows,View on GitHub (pinned to 1136503c6a)
Solutions
- Reduce anim.frames to be less than or equal to columns (the message states columns).
- Or widen the sheet / reduce frame.width to increase columns.
- Re-export the bundle after fixing pet.json.
Example fix
// before — 8-column sheet, animation claims 10 frames
{ "animations": { "run": { "row": 1, "frames": 10 } } }
// after
{ "animations": { "run": { "row": 1, "frames": 8 } } } Defensive patterns
Strategy: validation
Validate before calling
function validateAnimationsFrames(animations: Record<string, {frames:number}>, columns: number) {
for (const [name, a] of Object.entries(animations)) {
if (a.frames > columns) throw new Error(`animation ${name} frames ${a.frames} exceed columns ${columns}`)
}
} Try / catch
try { await importPetBundle(p) }
catch (e) { if (e instanceof Error && /frames but sheet only has/.test(e.message)) { /* reduce frames or widen sheet */ } else throw e } Prevention
- Count the columns in your sheet and never declare more frames per animation than columns.
- Re-validate animations whenever the sheet width or frame width changes.
When it happens
Trigger: An animation sets frames: 10 but the sheet only has 8 columns. Runs inside the manifest.animations loop at line 348.
Common situations: Author miscounted columns; frame.width was set too large reducing columns; animation 'frames' confused with total frames across the row.
Related errors
- Animation "${name}" references row ${anim.row} but sheet has
- 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/e8b6b28aeda22968.
Report an issue: GitHub.