Hmbown/CodeWhale · error · Error
The pet recording segment has changed.
Error message
The pet recording segment has changed.
What it means
prepareSegment archives consumed input by capturing a next checkpoint and returning a commit() closure. commit() re-verifies that the world has not advanced or mutated since the checkpoint was taken: it fails if commit was already called, this.origin changed, or this.tick moved past c.tick. This error means the segment changed between snapshot and commit, so splicing the logs would corrupt the replay.
Solutions
- Call commit() synchronously immediately after prepareSegment(), before any tick runs.
- Track and remove the duplicate commit call (the committed flag guards double invocation).
- Pause the tick loop (or snapshot under the same lock) while a segment commit is pending.
- If the world legitimately advanced, discard this prepareSegment result and call prepareSegment() again on the current state.
Example fix
// before const seg = world.prepareSegment(); world.tick(dt); // world advanced seg.commit(); // throws // after const seg = world.prepareSegment(); seg.commit(); // commit first world.tick(dt); // then continue simulating
Defensive patterns
Strategy: try-catch
Validate before calling
let tickBefore = world.tick; const seg = world.prepareSegment(); const canCommit = world.origin === segBeforeOrigin && world.tick === tickBefore;
Try / catch
const seg = world.prepareSegment();
try { seg.commit(); }
catch (e) {
if (e.message === 'The pet recording segment has changed.') {
// world ticked mid-archive: discard and retry on current state
const retry = world.prepareSegment(); retry.commit();
} else throw e;
} Prevention
- Call commit() synchronously right after prepareSegment(), before any tick.
- Never call commit() twice; treat the returned object as single-use.
- Freeze the tick loop (or hold a lock) while a segment archive is pending.
- Do not share a live PetWorld across concurrent features during export.
When it happens
Trigger: Calling commit() twice; ticking the PetWorld (advancing this.tick) or changing origin between prepareSegment() and commit(); concurrent code paths mutating the world while a segment archive is pending.
Common situations: A game loop tick firing during a long-running export; a retry wrapper that calls commit twice; sharing one PetWorld across modules where another feature calls tick() mid-archive.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- The pet recording segment has changed.
- A cancelled Operation cannot be edited.
- A saved trace identifier collided. Try saving again.
- a window change is already in progress
- another Codewhale process
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/59d03fbdd1e8fe8b.
Report an issue: GitHub.
Appendix: source
Thrown at pet/ios/Resources/pet-native.js:288
/** Retire only consumed input. The exact origin makes each archived segment
* independently replayable; no particle, random stream or score is reset. */
prepareSegment() {
const dropTape = Math.max(0, this.bucketIndex), dropInputs = this.interactionIndex, previous = this.origin;
const tape = this.tapeLog.slice(dropTape), interactions = this.interactionLog.slice(dropInputs);
const points = this.sim.p.map(p => [p.hx, p.hy]);
const c = this.checkpoint();
c.petCheckpointVersion = 2;
c.historyStart = this.tick;
c.hasTelemetry = this.hasTelemetry;
c.bucketIndex -= dropTape;
c.interactionIndex = 0;
c.history = new PetWorld(points, tape, interactions, this.sim.expressionVersion, true).historyDigest();
const next = PetWorld.restore(points, tape, interactions, c);
next.origin = next.checkpoint();
let committed = false;
return { recording: next.recording(), archive: this.recording(true, true), commit: () => {
if (committed || this.origin !== previous || this.tick < c.tick)
throw new Error('The pet recording segment has changed.');
this.tapeLog.splice(0, dropTape);
this.interactionLog.splice(0, dropInputs);
this.bucketIndex -= dropTape;
this.interactionIndex -= dropInputs;
this.tapeHashes = [];
this.hashTape(0);
this.segmented = true;
this.origin = next.origin;
committed = true;
} };
}
/** Lossless version 1 export, including the current pose and score. Drivers
* consume all chunks synchronously on the world's owner before another tick.
* Only a small slice is serialized inside an embedded runtime at a time. */
recordingChunk(index, completed = false) {
if (!Number.isSafeInteger(index) || index < 0)
throw new Error('Invalid pet export cursor.');
const size = 16, tapeEnd = completed ? this.bucketIndex + 1 : this.tapeLog.length;View on GitHub (pinned to 433685b202)