Hmbown/CodeWhale · error · Error
Pet checkpoint telemetry does not match its clock.
Error message
Pet checkpoint telemetry does not match its clock.
What it means
PetWorld independently verifies that the telemetry snapshot stored in the checkpoint equals the tape bucket the checkpoint's clock currently falls inside (candidate bucket where frame.timeMs < simTimeMs + durationMs, or undefined in a gap). If the serialized telemetry does not match the reconstructed bucket, the checkpoint's clock and telemetry are out of sync. Throwing prevents rendering telemetry that contradicts the restored timeline.
Solutions
- Re-capture the checkpoint so frame.telemetry and frame.timeMs are written atomically from the same tick.
- Update the checkpoint's frame.telemetry to match the tape bucket at bucketIndex (or null when in a gap).
- Migrate checkpoints saved by older versions to the current telemetry format before restore.
- Verify the tape used at restore is the same one the checkpoint was recorded against.
Example fix
// before: stale telemetry from a replaced bucket c.frame.telemetry = oldBucket; // throws on restore // after: recompute telemetry from the restored tape const cand = world.tape[c.bucketIndex]; c.frame.telemetry = cand && c.frame.timeMs < cand.simTimeMs + cand.durationMs ? cand : undefined;
Defensive patterns
Strategy: validation
Validate before calling
function telemetryMatchesClock(c, tape) {
const cand = tape[c.bucketIndex];
const expected = cand && c.frame.timeMs < cand.simTimeMs + cand.durationMs ? cand : undefined;
return JSON.stringify(c.frame.telemetry) === JSON.stringify(expected);
} Type guard
const hasCoherentTelemetry = (c) => (c?.frame?.telemetry ?? undefined) !== undefined ? typeof c.frame.telemetry === 'object' : true;
Try / catch
try {
world.resumeFromCheckpoint(c);
} catch (e) {
if (e.message === 'Pet checkpoint telemetry does not match its clock.') {
c.frame.telemetry = recomputeTelemetry(c, tape);
world.resumeFromCheckpoint(c);
} else throw e;
} Prevention
- Write frame.timeMs and frame.telemetry in the same atomic snapshot
- Recompute telemetry from the tape instead of trusting a stale serialized copy
- Version the checkpoint format and migrate telemetry fields on upgrade
- Never edit frame.timeMs without recomputing telemetry
When it happens
Trigger: Restoring a checkpoint whose frame.telemetry was captured against a different bucket than c.bucketIndex implies, or whose frame.timeMs sits in a gap but frame.telemetry is non-null (or vice versa) — a strict JSON deep-equality failure between c.frame.telemetry and the recomputed bucket.
Common situations: Older checkpoint format without telemetry field restored under new code; partial checkpoint writes; manually editing frame.timeMs or telemetry in a saved checkpoint; checkpoints exported before a telemetry bucket was replaced by acceptTelemetry.
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
- Pet checkpoint telemetry does not match its clock.
- Pet checkpoint does not match its recording.
- Pet checkpoint does not match its recording.
- Pet checkpoint telemetry does not match its clock.
- Pet segment checkpoints do not agree.
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1d73c5938c88792b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/pet_watch/pet-native.js:386
const world = new PetWorld(points, tape, interactions, c.sim?.expressionVersion ?? 1, c.petCheckpointVersion === 2);
if (c.petCheckpointVersion === 2) {
world.hasTelemetry = c.hasTelemetry;
world.origin = structuredClone(c);
}
if (c.history !== world.historyDigest()
|| c.bucketIndex >= 0 && world.tape[c.bucketIndex].simTimeMs > c.frame.timeMs + 1e-7
// acceptTelemetry may fill past gaps after the most recent fixed tick.
// Preserve that pending cursor exactly; it may lag only over empty gaps.
|| world.tape.some((b, i) => i > c.bucketIndex && b.simTimeMs <= c.frame.timeMs + 1e-7
&& (b.observed !== 0 || b.channel !== 'other' || b.errors || b.waiting || b.agentIds.length
|| b.onsets.some(Boolean) || b.activeMs.some(Boolean)))
|| world.interactionLog.slice(0, c.interactionIndex).some(e => e.timeMs > c.frame.timeMs + 1e-7)
|| world.interactionLog[c.interactionIndex]?.timeMs <= c.frame.timeMs + 1e-7)
throw new Error('Pet checkpoint does not match its recording.');
const candidate = world.tape[c.bucketIndex];
const telemetry = candidate && c.frame.timeMs < candidate.simTimeMs + candidate.durationMs ? candidate : undefined;
if (JSON.stringify(c.frame.telemetry) !== JSON.stringify(telemetry))
throw new Error('Pet checkpoint telemetry does not match its clock.');
world.sim.restore(c.sim);
world.score.restore(c.score);
world.random.restore(c.random);
world.accumulator = c.accumulator;
world.tick = c.tick;
world.bucketIndex = c.bucketIndex;
world.interactionIndex = c.interactionIndex;
world.branchTick = c.branchTick;
world.behaviour = c.behaviour;
world.until = c.until;
world.targetX = c.targetX;
world.targetY = c.targetY;
world.x = c.x;
world.y = c.y;
world.flip = c.flip;
world.lit = c.lit;
world.lastActivity = c.lastActivity;
world.addressedAt = c.addressedAt ?? -Infinity;View on GitHub (pinned to 73e0f67d83)