Hmbown/CodeWhale · error · Error

Pet segment checkpoints do not agree.

Error message

Pet segment checkpoints do not agree.

What it means

When a recording carries both a start checkpoint and a later checkpoint, fromRecording restores from the later checkpoint and cross-checks it against the start: the restored world must be segmented, must not be at an earlier tick than the start, and the checkpoint's historyStart must equal the start's tick. Any disagreement means the two checkpoints were not taken from the same continuous recording lineage.

Solutions

  1. Re-export start and checkpoint together from the same PetWorld via recording()/prepareSegment so their metadata is consistent.
  2. Ensure checkpoint.historyStart equals start.tick before assembling the recording.
  3. Drop one of the two checkpoints if they are not from the same lineage and replay from the remaining anchor.

Example fix

// before
rec.start = oldSegmentStart; rec.checkpoint = checkpointFromOtherSession; // throws
// after
const { recording } = world.prepareSegment(points, tape, interactions, dropTape, dropInputs);
const rec = JSON.parse(recording); // consistent start + checkpoint
Defensive patterns

Strategy: validation

Validate before calling

if (rec.start && rec.checkpoint && rec.checkpoint.historyStart !== rec.start.tick)
  throw new Error('start/checkpoint lineage mismatch before fromRecording');

Type guard

function checkpointsAgree(r: PetRecording): boolean {
  return !r.start || !r.checkpoint || r.checkpoint.historyStart === r.start.tick;
}

Try / catch

try {
  return PetWorld.fromRecording(points, rec);
} catch (e) {
  if (e.message === 'Pet segment checkpoints do not agree.') {
    // re-export both checkpoints together from the same world
  } else throw e;
}

Prevention

When it happens

Trigger: Calling PetWorld.fromRecording(points, value) where r.start and r.checkpoint come from different recordings, the checkpoint's historyStart does not match start.tick, or the checkpoint's tape index lands before the start tick.

Common situations: Splicing checkpoints from different sessions; re-archiving a segment so its historyStart moved while an old start checkpoint was retained; manually assembling a recording from partial exports.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/5d5a994cce9730d9. Report an issue: GitHub.

Appendix: source

Thrown at pet/src/core/pet-world.ts:148

    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);
    const points = this.sim.p.map(p => [p.hx, p.hy] as [number, number]);
    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: () => {

View on GitHub (pinned to 433685b202)