Hmbown/CodeWhale · error · Error
Unsupported pet expression version.
Error message
Unsupported pet expression version.
What it means
fromRecording resolves the expression version from r.expressionVersion (defaulting to 1 for legacy recordings) and only supports versions 1 and 2. A recording produced with a newer expression/simulation format cannot be interpreted by this binary, so the library refuses it rather than rendering a wrong pet.
Solutions
- Upgrade the application/binary to a version that supports the recording's expressionVersion.
- Re-export the recording from the newer version in a supported format.
- Fix the expressionVersion field if it was accidentally edited or corrupted (must be 1 or 2).
- Discard the recording if no compatible producer is available.
Example fix
// before // recording has expressionVersion: 3, loaded by binary supporting 1-2 const world = PetWorld.fromRecording(points, r); // throws // after // upgrade the app, or strip/convert: r.expressionVersion = 2; // only if you know the semantics did not change const world = PetWorld.fromRecording(points, r);
Defensive patterns
Strategy: validation
Validate before calling
if (r.expressionVersion !== undefined && ![1, 2].includes(r.expressionVersion))
throw new Error(`Recording needs app supporting expressionVersion ${r.expressionVersion}`); Try / catch
try {
world = PetWorld.fromRecording(points, r);
} catch (err) {
if (err.message === 'Unsupported pet expression version.')
notifyUser('Upgrade the app to open this recording.');
else throw err;
} Prevention
- Check expressionVersion against the app's supported range before loading.
- Gate recording files with a format/version manifest written at export time.
- Pin recordings to the app version that produced them when archiving.
- Never hand-edit version fields in recording files.
When it happens
Trigger: Calling `PetWorld.fromRecording(points, r)` where r.expressionVersion is a number other than 1 or 2 (e.g. 3 from a newer app version, or a corrupted/garbage value like a string).
Common situations: Opening a recording exported by a newer release of the app in an older binary; a version field corrupted during transfer; hand-editing a recording file and mistyping the version.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Codewhale stream-json schema did not match v0.9.1
- Invalid legacy pet recording.
- Item schema v is newer than supported v
- Pet expression version does not match its checkpoint.
- Thread schema v is newer than supported v
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/471d130c3b36aa30.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/pet_watch/pet-native.js:251
waitSince: this.waitSince, food: this.food, members: [...this.members.values()], lastStill: this.lastStill,
frame: this.frame, voices: this.voices });
}
recording(withCheckpoint = true, completed = false) {
const tapeEnd = completed ? this.bucketIndex + 1 : this.tapeLog.length;
const inputEnd = completed ? this.interactionIndex : this.interactionLog.length;
const history = this.historyDigest(tapeEnd, inputEnd);
return { petReplayVersion: this.segmented ? 2 : 1, expressionVersion: this.sim.expressionVersion,
tape: this.tapeLog.slice(0, tapeEnd), interactions: this.interactionLog.slice(0, inputEnd).map(e => ({ ...e })),
...(this.origin ? { start: { ...structuredClone(this.origin), hasTelemetry: this.hasTelemetry, history } } : {}),
...(withCheckpoint ? { checkpoint: { ...this.checkpoint(), history } } : {}) };
}
static fromRecording(points, value) {
const r = value;
if (!r || ![1, 2].includes(r.petReplayVersion) || !Array.isArray(r.tape) || !Array.isArray(r.interactions))
throw new Error('Invalid pet recording.');
const version = r.expressionVersion === undefined ? 1 : r.expressionVersion;
if (![1, 2].includes(version))
throw new Error('Unsupported pet expression version.');
if (r.checkpoint !== undefined && !r.checkpoint || r.start !== undefined && !r.start)
throw new Error('Invalid pet checkpoint.');
for (const c of [r.start, r.checkpoint])
if (c && (c.sim?.expressionVersion ?? 1) !== version)
throw new Error('Pet expression version does not match its checkpoint.');
if (r.petReplayVersion === 1 && (r.start || r.checkpoint && r.checkpoint.petCheckpointVersion !== 1))
throw new Error('Invalid legacy pet recording.');
if (r.petReplayVersion === 2 && (!r.start || r.start.petCheckpointVersion !== 2 || r.start.historyStart !== r.start.tick))
throw new Error('The recording segment is missing its starting checkpoint.');
const first = r.start && PetWorld.restore(points, r.tape, r.interactions, r.start);
const world = r.checkpoint ? PetWorld.restore(points, r.tape, r.interactions, r.checkpoint) : first ?? new PetWorld(points, r.tape, r.interactions, version);
if (first) {
if (!world.segmented || world.tick < first.tick || r.checkpoint && r.checkpoint.historyStart !== first.tick)
throw new Error('Pet segment checkpoints do not agree.');
world.origin = first.checkpoint();
}
return world;
}View on GitHub (pinned to 73e0f67d83)