Hmbown/CodeWhale · error · Error

Invalid pet duration.

Error message

Invalid pet duration.

What it means

Guard at the top of compilePetTelemetry: fires when the durationMs argument is not a finite number or is negative (NaN, Infinity, or < 0). The caller passed an invalid trace duration; only a finite non-negative duration can be divided into pet buckets.

Solutions

  1. Clamp the duration: Math.max(0, endMs - startMs) and verify Number.isFinite before calling
  2. Default missing end timestamps to start (zero duration) or to now
  3. Validate timestamps at the span-producing layer so bad spans never reach compile
  4. Skip spans with non-finite timestamps and log them

Example fix

// before
compilePetTelemetry(events, endMs - startMs); // NaN if startMs undefined
// after
const duration = Number.isFinite(endMs - startMs) ? Math.max(0, endMs - startMs) : 0;
compilePetTelemetry(events, duration);
Defensive patterns

Strategy: validation

Validate before calling

const duration = endMs != null && Number.isFinite(endMs - startMs) ? Math.max(0, endMs - startMs) : 0;
if (!Number.isFinite(duration) || duration < 0) throw new Error('bad duration before compile');

Type guard

function isValidDuration(ms: unknown): ms is number {
  return typeof ms === 'number' && Number.isFinite(ms) && ms >= 0;
}

Try / catch

try {
  compilePetTelemetry(events, duration);
} catch (e) {
  if (e.message === 'Invalid pet duration.') {
    compilePetTelemetry(events, 0); // treat as zero-duration window
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a durationMs that is NaN (e.g. from a failed Date arithmetic or undefined subtraction), negative (end before start), or Infinity (missing end timestamp).

Common situations: Computing duration as Date.now() - undefinedStart; a span whose end timestamp was absent so subtraction yielded NaN; timezone/clock adjustments producing negative windows; JSON round-trips turning a number into null then NaN via coercion.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at pet/src/core/pet-telemetry.ts:72

    try { packet = JSON.parse(line); validatePetBucket(packet); }
    catch (error) { this.reset(); throw error; }
    const previous = this.sequence; this.sequence = packet.sequence;
    if (previous === undefined || packet.sequence <= previous) return;
    return packet;
  }
}

const order = (a: string, b: string) => a < b ? -1 : a > b ? 1 : 0;
const keyOf = (e: WhaleEvent) => JSON.stringify([e.traceId, e.id]);
const isContainer = (e: WhaleEvent) => e.attributes['whalesong.container'] === true
  || e.attributes['codewhale.container'] === true;

/** Compile a single trace. Unknown-duration spans provide onsets, not occupancy.
 * Updates of the same trace/id replace earlier snapshots rather than double count.
 * An endpoint onset gets its own bucket; intervals use [start, end). */
export function compilePetTelemetry(input: readonly WhaleEvent[], durationMs = 0, firstSequence = 0, originMs = 0): PetBucket[] {
  if (input.length > 250_000) throw new Error('Pet input exceeds 250000 events.');
  if (!Number.isFinite(durationMs) || durationMs < 0) throw new Error('Invalid pet duration.');
  if (!Number.isSafeInteger(firstSequence) || firstSequence < 0) throw new Error('Invalid first pet bucket.');
  if (!Number.isFinite(originMs)) throw new Error('Invalid pet clock origin.');
  durationMs = Math.max(0, durationMs - originMs);
  const unique = new Map<string, WhaleEvent>();
  const traces = new Set<string>();
  for (const e of input) {
    if (e.schemaVersion !== 1 || !e.id || !e.traceId || !CATEGORIES.includes(e.category)
      || !Number.isFinite(e.startTime) || !Number.isFinite(e.endTime)
      || e.startTime < 0 || e.endTime < e.startTime || !e.attributes)
      throw new Error('Invalid event-v1 pet input. Import through importTrace first.');
    traces.add(e.traceId); unique.set(keyOf(e), e);
  }
  if (traces.size > 1) throw new Error('Select one trace for the pet.');
  const parents = new Set([...unique.values()].filter(e => e.parentId).map(e => e.parentId!));
  const events = [...unique.values()].filter(e => !isContainer(e)
    && !(e.category === 'orchestration' && parents.has(e.id)))
    .map(e => ({ ...e, startTime: e.startTime - originMs, endTime: (e.openEnded ? e.startTime : e.endTime) - originMs,
      attributes: e.attributes['whalesong.error_onset_ms'] === undefined ? e.attributes

View on GitHub (pinned to 433685b202)