Hmbown/CodeWhale · error · NSError(CodewhalePet)
1
1
Error message
The particle checkpoint does not match this whale.
What it means
PetSim throws NSError(domain: "CodewhalePet", code: 1) with this message at PetSim.swift:301 when a deserialized particle checkpoint fails structural validation: wrong version, expressionVersion outside {1,2}, body/particle-array length mismatched with the live particle count, color not exactly 3 channels, channel indices out of range, per-particle body triplets not matching the current particle state (hx, hy, s), or non-finite particle values. The store refuses to apply a checkpoint that does not describe this exact whale.
Solutions
- Delete or rename the incompatible `<source>.json` (and stale `-segment-` archives) so the app starts a fresh checkpoint.
- Verify the checkpoint belongs to the same whale — do not copy habitat files between accounts/devices.
- Upgrade or downgrade the app so its expressionVersion set matches the checkpoint's (accepted: 1 or 2, defaulting to 1).
- If you produce checkpoints programmatically, ensure body triplets equal the live particles' (hx, hy, s) and all particle fields are finite before saving.
Example fix
// before: blindly applying a foreign checkpoint
try pet.apply(checkpoint)
// after: pre-validate shape and count against the live whale
guard checkpoint.particles.count == pet.particleCount,
checkpoint.version == 1 else {
logger.warning("checkpoint incompatible; resetting")
try? FileManager.default.removeItem(at: habitatFile)
return
}
try pet.apply(checkpoint) Defensive patterns
Strategy: validation
Validate before calling
// Validate checkpoint shape before applying
func checkpointMatches(_ c: Checkpoint, p: [Particle]) -> Bool {
c.version == 1
&& [1, 2].contains(c.expressionVersion ?? 1)
&& c.body.count == p.count && c.particles.count == p.count
&& c.color.count == 3
&& c.particles.allSatisfy { $0.count == 8 && $0.allSatisfy(\.isFinite) }
} Type guard
func isCheckpointMismatch(_ e: Error) -> Bool {
let n = e as NSError
return n.domain == "CodewhalePet" && n.code == 1
&& n.localizedDescription.contains("checkpoint does not match")
} Try / catch
do { try pet.apply(checkpoint) }
catch let e as NSError where isCheckpointMismatch(e) {
logger.warning("incompatible checkpoint; resetting habitat")
try? resetHabitat()
} Prevention
- Never copy habitat JSON between different whales or devices.
- Version-gate checkpoints when changing particle layout across releases.
- Ensure saved particle triplets equal the live (hx, hy, s) and all values are finite.
When it happens
Trigger: Applying a checkpoint from a different whale/pet instance; loading a save written by an older or newer version with a different particle count or expression version; hand-edited or truncated JSON in the habitat store; corrupted archive segments.
Common situations: Restoring a backup from another device whose pet evolved differently; version migration between app releases changed checkpoint layout; file corruption from an interrupted sync.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- CodewhalePet/1
- Invalid pet particle checkpoint.
- Invalid pet particle checkpoint.
- Invalid pet particle checkpoint.
- Invalid pet random stream.
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/693a9984769b04d8.
Report an issue: GitHub.
Appendix: source
Thrown at pet/swift/PetSim.swift:301
q.ang = atan2(q.hy, q.hx)
q.rad = (q.hx * q.hx + q.hy * q.hy).squareRoot()
q.tail = clamp01(((-q.hx - q.hy) * 0.5 + 0.22) / 0.62)
return q
}
cur = channelIndex("reasoning")!
prev = cur
}
func restoreValidated(_ checkpoint: PetParticleCheckpoint) throws {
// Array and identity checks also protect this native boundary if its
// caller changes. Mutation starts only after the complete shape passes.
guard checkpoint.version == 1, [1, 2].contains(checkpoint.expressionVersion ?? 1), checkpoint.body.count == p.count,
checkpoint.particles.count == p.count, checkpoint.color.count == 3,
CHANNELS.indices.contains(checkpoint.previous), CHANNELS.indices.contains(checkpoint.current),
checkpoint.body.enumerated().allSatisfy({ i, v in
v.count == 3 && v[0] == p[i].hx && v[1] == p[i].hy && v[2] == p[i].s
}), checkpoint.particles.allSatisfy({ $0.count == 8 && $0.allSatisfy(\.isFinite) })
else { throw NSError(domain: "CodewhalePet", code: 1, userInfo: [NSLocalizedDescriptionKey: "The particle checkpoint does not match this whale."]) }
expressionVersion = checkpoint.expressionVersion ?? 1
phase = checkpoint.phase; clock = checkpoint.clock; tear = checkpoint.tear
prev = checkpoint.previous; cur = checkpoint.current
col = (checkpoint.color[0], checkpoint.color[1], checkpoint.color[2]); frame = checkpoint.frame
for i in p.indices {
let v = checkpoint.particles[i]
p[i].x = v[0]; p[i].y = v[1]; p[i].vx = v[2]; p[i].vy = v[3]
p[i].jx = v[4]; p[i].jy = v[5]; p[i].tx = v[6]; p[i].ty = v[7]
}
}
/// Advance the sim by dt seconds under `state`. Identical math to PetSim.ts.
public func step(dt: Double, state: PetState, motion: Bool = true, sensitivity: Double = 1, podSlots: [(Int, Double)]? = nil) {
let s: (Double) -> Double = { lerp(0.5, $0, sensitivity) }
let act = s(state.activity), coh = s(state.coherence), att = s(state.attention)
let seen = s(state.observed)
let mot = motion ? 1.0 : 0.0
phase += dt * (0.18 + act * 0.55) * motView on GitHub (pinned to 433685b202)