Hmbown/CodeWhale · error · Error

Invalid first pet bucket.

Error message

Invalid first pet bucket.

What it means

compilePetTelemetry requires firstSequence to be a safe non-negative integer, because it is used directly as the starting bucket sequence number. Floats, negatives, or numbers beyond Number.MAX_SAFE_INTEGER throw this error.

Solutions

  1. Floor and validate: Math.floor(firstSequence), and clamp at 0 before calling
  2. Pass the explicit default 0 when starting a fresh tape
  3. Compute sequence numbers with Math.floor(originMs / PET_BIN_MS) and assert Number.isSafeInteger
  4. Skip compilation when the computed first sequence is invalid and log the cause

Example fix

// before
compilePetTelemetry(events, duration, elapsedMs / PET_BIN_MS);
// after
const first = Math.max(0, Math.floor(elapsedMs / PET_BIN_MS));
compilePetTelemetry(events, duration, Number.isSafeInteger(first) ? first : 0);
Defensive patterns

Strategy: validation

Validate before calling

const first = Math.max(0, Math.floor(elapsedMs / PET_BIN_MS));
if (!Number.isSafeInteger(first)) throw new Error('bad firstSequence before compile');

Type guard

function isValidFirstSequence(n: unknown): n is number {
  return typeof n === 'number' && Number.isSafeInteger(n) && n >= 0;
}

Try / catch

try {
  compilePetTelemetry(events, duration, firstSequence);
} catch (e) {
  if (e.message === 'Invalid first pet bucket.') {
    compilePetTelemetry(events, duration, 0); // restart tape numbering
  } else throw e;
}

Prevention

When it happens

Trigger: Calling compilePetTelemetry with firstSequence = -1, a fractional value from division, NaN, or an unbounded computed offset (e.g. ms-since-epoch divided by PET_BIN_MS without flooring/clamping).

Common situations: Computing the first bucket as Date.now()/PET_BIN_MS and getting a float; an uninitialized variable defaulting to NaN; a negative offset from a clock-origin subtraction gone wrong.

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/c6edaff353f2fe1a. Report an issue: GitHub.

Appendix: source

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

    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
        : { ...e.attributes, 'whalesong.error_onset_ms': errorOnsetOf(e) - originMs } }))

View on GitHub (pinned to 433685b202)