Hmbown/CodeWhale · error · Error

Invalid pet checkpoint.

Error message

Invalid pet checkpoint.

What it means

fromRecording allows 'start' and 'checkpoint' to be absent, but if either key is present its value must be a truthy checkpoint object. This error means a recording explicitly contains start or checkpoint set to null/false/0/empty — a structurally broken serialization.

Solutions

  1. Delete the null start/checkpoint keys instead of serializing them (omit the field entirely).
  2. Re-export the recording from the originating world via recording()/recordingChunk().
  3. Fix the producer to use conditional spread: ...(checkpoint ? { checkpoint } : {}).
  4. If you only have a null checkpoint, restore from start only, or rebuild the world from the tape.

Example fix

// before
const fixed = { ...r, checkpoint: r.checkpoint ?? null };
// after
const fixed = { ...r };
if (!fixed.checkpoint) delete fixed.checkpoint;
if (!fixed.start) delete fixed.start;
const world = PetWorld.fromRecording(points, fixed);
Defensive patterns

Strategy: validation

Validate before calling

for (const k of ['start','checkpoint']) if (r[k] !== undefined && !r[k]) throw new Error(k + ' present but falsy');

Type guard

const hasValidCheckpoints = (r: any) =>
  (r.start === undefined || !!r.start) && (r.checkpoint === undefined || !!r.checkpoint);

Try / catch

try { world = PetWorld.fromRecording(points, r); }
catch (e) {
  if (e.message === 'Invalid pet checkpoint.') {
    delete r.start; delete r.checkpoint; // retry without checkpoints
    world = PetWorld.fromRecording(points, r);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a recording where r.checkpoint or r.start is present but falsy (null, undefined via explicit key, 0, '').

Common situations: A serializer that writes "checkpoint": null instead of omitting the key; manual JSON editing; a partial export pipeline that zeroes out the checkpoint field.

Related errors


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

Appendix: source

Thrown at pet/ios/Resources/pet-native.js:253

    }
    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;
    }
    /** Retire only consumed input. The exact origin makes each archived segment
     * independently replayable; no particle, random stream or score is reset. */

View on GitHub (pinned to 433685b202)