{"record":{"id":"05d7703c4158d73c","repo":"Hmbown/CodeWhale","slug":"invalid-pet-checkpoint-native","errorCode":null,"errorMessage":"Invalid pet checkpoint.","messagePattern":"Invalid pet checkpoint\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/ios/Resources/pet-native.js","lineNumber":253,"sourceCode":"    }\n    recording(withCheckpoint = true, completed = false) {\n        const tapeEnd = completed ? this.bucketIndex + 1 : this.tapeLog.length;\n        const inputEnd = completed ? this.interactionIndex : this.interactionLog.length;\n        const history = this.historyDigest(tapeEnd, inputEnd);\n        return { petReplayVersion: this.segmented ? 2 : 1, expressionVersion: this.sim.expressionVersion,\n            tape: this.tapeLog.slice(0, tapeEnd), interactions: this.interactionLog.slice(0, inputEnd).map(e => ({ ...e })),\n            ...(this.origin ? { start: { ...structuredClone(this.origin), hasTelemetry: this.hasTelemetry, history } } : {}),\n            ...(withCheckpoint ? { checkpoint: { ...this.checkpoint(), history } } : {}) };\n    }\n    static fromRecording(points, value) {\n        const r = value;\n        if (!r || ![1, 2].includes(r.petReplayVersion) || !Array.isArray(r.tape) || !Array.isArray(r.interactions))\n            throw new Error('Invalid pet recording.');\n        const version = r.expressionVersion === undefined ? 1 : r.expressionVersion;\n        if (![1, 2].includes(version))\n            throw new Error('Unsupported pet expression version.');\n        if (r.checkpoint !== undefined && !r.checkpoint || r.start !== undefined && !r.start)\n            throw new Error('Invalid pet checkpoint.');\n        for (const c of [r.start, r.checkpoint])\n            if (c && (c.sim?.expressionVersion ?? 1) !== version)\n                throw new Error('Pet expression version does not match its checkpoint.');\n        if (r.petReplayVersion === 1 && (r.start || r.checkpoint && r.checkpoint.petCheckpointVersion !== 1))\n            throw new Error('Invalid legacy pet recording.');\n        if (r.petReplayVersion === 2 && (!r.start || r.start.petCheckpointVersion !== 2 || r.start.historyStart !== r.start.tick))\n            throw new Error('The recording segment is missing its starting checkpoint.');\n        const first = r.start && PetWorld.restore(points, r.tape, r.interactions, r.start);\n        const world = r.checkpoint ? PetWorld.restore(points, r.tape, r.interactions, r.checkpoint) : first ?? new PetWorld(points, r.tape, r.interactions, version);\n        if (first) {\n            if (!world.segmented || world.tick < first.tick || r.checkpoint && r.checkpoint.historyStart !== first.tick)\n                throw new Error('Pet segment checkpoints do not agree.');\n            world.origin = first.checkpoint();\n        }\n        return world;\n    }\n    /** Retire only consumed input. The exact origin makes each archived segment\n     * independently replayable; no particle, random stream or score is reset. */","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/ios/Resources/pet-native.js#L235-L271","documentation":"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.","triggerScenarios":"Passing a recording where r.checkpoint or r.start is present but falsy (null, undefined via explicit key, 0, '').","commonSituations":"A serializer that writes \"checkpoint\": null instead of omitting the key; manual JSON editing; a partial export pipeline that zeroes out the checkpoint field.","solutions":["Delete the null start/checkpoint keys instead of serializing them (omit the field entirely).","Re-export the recording from the originating world via recording()/recordingChunk().","Fix the producer to use conditional spread: ...(checkpoint ? { checkpoint } : {}).","If you only have a null checkpoint, restore from start only, or rebuild the world from the tape."],"exampleFix":"// before\nconst fixed = { ...r, checkpoint: r.checkpoint ?? null };\n// after\nconst fixed = { ...r };\nif (!fixed.checkpoint) delete fixed.checkpoint;\nif (!fixed.start) delete fixed.start;\nconst world = PetWorld.fromRecording(points, fixed);","handlingStrategy":"validation","validationCode":"for (const k of ['start','checkpoint']) if (r[k] !== undefined && !r[k]) throw new Error(k + ' present but falsy');","typeGuard":"const hasValidCheckpoints = (r: any) =>\n  (r.start === undefined || !!r.start) && (r.checkpoint === undefined || !!r.checkpoint);","tryCatchPattern":"try { world = PetWorld.fromRecording(points, r); }\ncatch (e) {\n  if (e.message === 'Invalid pet checkpoint.') {\n    delete r.start; delete r.checkpoint; // retry without checkpoints\n    world = PetWorld.fromRecording(points, r);\n  } else throw e;\n}","preventionTips":["Omit null checkpoint fields instead of serializing them (use conditional spread).","Normalize deserialized recordings: strip keys whose value is null.","Keep serialization and deserialization in one module so key presence stays symmetric."],"tags":["validation","replay","null"],"backgroundTag":"null-argument","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}