Hmbown/CodeWhale · error · Error
Unsupported pet expression version.
Error message
Unsupported pet expression version.
What it means
Thrown by PetWorld.fromRecording when the recording's expressionVersion is not one this build understands. Recordings persist the simulator's expressionVersion; a recording produced by a newer (or unknown) simulator cannot be replayed faithfully, so restoring is refused instead of misinterpreting expression state.
Solutions
- Upgrade the app/library to a version supporting the recording's expressionVersion.
- Re-record or re-export the pet with a supported expression version (1 or 2).
- Fix or remove the corrupted expressionVersion field if the file was hand-edited.
Example fix
// before
const world = PetWorld.fromRecording(points, newRecordingFromFutureVersion);
// after
if (![1, 2].includes(newRecordingFromFutureVersion.expressionVersion)) {
throw new Error('Upgrade the app to load this recording.');
}
const world = PetWorld.fromRecording(points, newRecordingFromFutureVersion); Defensive patterns
Strategy: validation
Validate before calling
const version = rec.expressionVersion ?? 1;
if (![1,2].includes(version)) throw new Error('expressionVersion ' + version + ' not supported; upgrade the app'); Try / catch
try { PetWorld.fromRecording(points, rec); } catch (e) { if (e.message.includes('expression version')) promptUpgrade(); } Prevention
- Persist expressionVersion with recordings and check it at load time.
- On app downgrade, refuse or migrate recordings rather than loading blindly.
When it happens
Trigger: Loading a recording whose expressionVersion is 0, 3, or any value other than 1/2 (undefined is allowed and means 1).
Common situations: Downgrading the app and opening recordings made by a newer version; hand-edited recording files; a corrupt expressionVersion field.
Related errors
- Codewhale stream-json schema did not match v0.9.1
- Item schema v is newer than supported v
- Thread schema v is newer than supported v
- Turn schema v is newer than supported v
- Unsupported pet expression version.
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/b9610f9662b416b4.
Report an issue: GitHub.
Appendix: source
Thrown at pet/src/core/pet-world.ts:140
waitSince: this.waitSince, food: this.food, members: [...this.members.values()], lastStill: this.lastStill,
frame: this.frame, voices: this.voices });
}
recording(withCheckpoint = true, completed = false): PetRecording {
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: [number, number][], value: unknown): PetWorld {
const r = value as PetRecording;
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;
}
/** Retire only consumed input. The exact origin makes each archived segment
* independently replayable; no particle, random stream or score is reset. */
prepareSegment(): PetSegment {
const dropTape = Math.max(0, this.bucketIndex), dropInputs = this.interactionIndex, previous = this.origin;
const tape = this.tapeLog.slice(dropTape), interactions = this.interactionLog.slice(dropInputs);View on GitHub (pinned to 433685b202)