Hmbown/CodeWhale · error · Error

No pet segment was prepared.

Error message

No pet segment was prepared.

What it means

commitSegment() finalizes a recording segment previously created with prepareSegment(). If prepareSegment() was never called — or the segment was already committed, which clears this.segment — the internal this.segment is undefined and the call throws. It is an ordering/state guard, not a data problem.

Solutions

  1. Gate the commit on needsSegment()/prepareSegment(): call prepareSegment() first, then commitSegment() exactly once
  2. Track a boolean 'segmentOpen' in the caller and skip the second commit
  3. Re-create the segment (prepareSegment) if the world was restored between prepare and commit
  4. Catch the error and treat it as a no-op if your commit path is idempotent by design

Example fix

// before
pet.commitSegment();
// after
if (pet.needsSegment() === false) { pet.prepareSegment(); }
pet.commitSegment();
Defensive patterns

Strategy: try-catch

Validate before calling

if (!segmentOpen) { pet.prepareSegment(); segmentOpen = true; }

Try / catch

try {
  pet.commitSegment();
  segmentOpen = false;
} catch (err) {
  if (err.message === 'No pet segment was prepared.') { segmentOpen = false; }
  else throw err;
}

Prevention

When it happens

Trigger: Calling pet.commitSegment() without a prior pet.prepareSegment(); calling commitSegment() twice in a row (the first commit sets this.segment = undefined); calling commitSegment() after restoreRecording/restoreCheckpoint, which reset this.segment to undefined.

Common situations: Double-flushing a recording pipeline; racing timers that both call commitSegment; restarting/restoring a session between prepare and commit.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at pet/src/core/pet-native.ts:54

    }
    return JSON.stringify({ ...frame, digest: digest(sim), style: sim.frame, activity: this.engine.activity(frame.timeMs),
      points: sim.p.map(p => [p.x, p.y]),
      still: { points: this.stillProjection.points, style: this.stillProjection.style, state } });
  }
  /** Losing a producer invalidates outstanding coverage, never the creature. */
  disconnectEngine(): void { this.engine = new PetEngineTelemetry(); this.world.voices = []; }
  interact(kind: PetInteraction['kind'], x: number, y: number): void { this.world.interact(kind, x, y); }
  interactions(): string { return JSON.stringify(this.world.interactions); }
  accept(packet: string): void { this.world.acceptTelemetry(JSON.parse(packet)); }
  acceptLiveTail(text: string): boolean {
    const packet = this.liveTape.readTail(text); if (!packet) return false;
    this.world.acceptTelemetry(packet); return true;
  }
  resetLiveInput(): number { this.liveTape.reset(); return this.resumeEngine(); }
  recording(withCheckpoint = false): string { return JSON.stringify(this.world.recording(withCheckpoint)); }
  needsSegment(): boolean { return this.world.needsSegment; }
  prepareSegment(): string { this.segment = this.world.prepareSegment(); return JSON.stringify(this.segment.recording); }
  commitSegment(): void { if (!this.segment) throw new Error('No pet segment was prepared.'); this.segment.commit(); this.segment = undefined; }
  checkpoint(): string { return JSON.stringify(this.world.checkpoint()); }
  recordingChunk(index: number, completed = false): string | null { return this.world.recordingChunk(index, completed); }
  restoreCheckpoint(text: string): void {
    if (text.length > 512 * 1024) throw new Error('Pet checkpoint exceeds its size limit.');
    this.restoreRecording(JSON.stringify({ ...this.world.recording(false), checkpoint: JSON.parse(text) }));
  }
  restoreRecording(text: string): void {
    if (text.length > 8 * 1024 * 1024) throw new Error('Native habitat exceeds 8 MiB.');
    const points = this.world.sim.p.map(p => [p.hx, p.hy] as [number, number]);
    this.world = PetWorld.fromRecording(points, JSON.parse(text));
    this.liveTape.reset();
    this.segment = undefined; this.engineTick = Math.round(this.world.frame.timeMs * 30 / 1000); this.engine = new PetEngineTelemetry();
  }
  /** Resume a live host at the first unrecorded bucket. Keep every accepted
   * interval, but never present its last observed frame as current evidence. */
  resumeEngine(): number {
    this.world.resumeObservation();
    this.engineTick = Math.round(this.world.frame.timeMs * 30 / 1000);

View on GitHub (pinned to 433685b202)