Hmbown/CodeWhale · error · Error

Invalid version 1 pet bucket.

Error message

Invalid version 1 pet bucket.

What it means

validatePetBucket checks each decoded version-1 pet bucket's shape: sequence-aligned simTimeMs and PET_BIN_MS durationMs, a channel present in CATEGORIES, boolean waiting, bounded agentIds (string, non-empty, <=4096 chars, <=250k), non-negative bounded errors count, and exactly 13-element onsets and activeMs arrays within bounds. A bucket failing any check throws 'Invalid version 1 pet bucket.'

Solutions

  1. Identify the offending row index from the JSONL file and log the full row; compare each field against the v1 constraints above.
  2. If the tape was written by another schema version, regenerate it with the current build instead of feeding it to the v1 validator.
  3. Repair specific defects: set simTimeMs = sequence * PET_BIN_MS, durationMs = PET_BIN_MS, pad/truncate onsets and activeMs to 13 elements, and drop invalid agentIds entries.
  4. Re-encode the tape after fixing, or discard the corrupt file and let the app rebuild it from the session log.

Example fix

// before
rows.map(JSON.parse).forEach(b => decodePetJSONL(b)); // b.onsets has 12 entries
// after
if (Array.isArray(b.onsets) && b.onsets.length === 13 &&
    Array.isArray(b.activeMs) && b.activeMs.length === 13) {
  decodePetJSONL(b);
} else {
  b.onsets = new Array(13).fill(0);
  b.activeMs = new Array(13).fill(0);
  decodePetJSONL(b);
}
Defensive patterns

Strategy: validation

Validate before calling

function bucketLooksValid(b, BIN_MS, CATEGORIES) {
  return b && typeof b === 'object' &&
    b.simTimeMs === b.sequence * BIN_MS && b.durationMs === BIN_MS &&
    CATEGORIES.includes(b.channel) && typeof b.waiting === 'boolean' &&
    Array.isArray(b.onsets) && b.onsets.length === 13 &&
    Array.isArray(b.activeMs) && b.activeMs.length === 13 &&
    Number.isSafeInteger(b.errors) && b.errors >= 0;
}

Type guard

const isPetBucketV1 = (b, BIN_MS, CATEGORIES) => bucketLooksValid(b, BIN_MS, CATEGORIES);

Try / catch

try {
  rows.forEach(validatePetBucket);
} catch (e) {
  if (e.message === 'Invalid version 1 pet bucket.') rebuildTapeFromSessionLog();
  else throw e;
}

Prevention

When it happens

Trigger: decodePetJSONL encountering a JSONL row whose bucket: has mismatched simTimeMs vs sequence*PET_BIN_MS, an unknown channel string, agentIds entries that are empty/oversized/non-string, negative errors, onsets/activeMs arrays of the wrong length (not 13) or containing out-of-range/NaN values.

Common situations: A pet tape file written by a different schema version (field renamed or missing, so the field is undefined and fails every typeof check); hand-assembled or corrupted rows; the v1 bucket written when PET_BIN_MS or the 13-channel layout differed from the current build.

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


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/9f25dde43a220fdf. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tui/pet_watch/pet-native.js:1111

exports.encodePetJSONL = encodePetJSONL;
exports.encodePetTSV = encodePetTSV;
const model_js_1 = require("./model.js");
const signal_js_1 = require("./signal.js");
const pet_sim_js_1 = require("./pet-sim.js");
/** One projection for imports, demos and recorded live snapshots. Times are ms.
 * These are aesthetic encodings of measured events, never model confidence. */
exports.PET_BIN_MS = 400;
function validatePetBucket(value) {
    (0, pet_sim_js_1.validatePetState)(value);
    const b = value;
    if (!b || typeof b !== 'object' || b.version !== 1 || !Number.isSafeInteger(b.sequence) || b.sequence < 0 || b.sequence > pet_sim_js_1.PET_MAX_SECONDS * 2.5
        || b.simTimeMs !== b.sequence * exports.PET_BIN_MS || b.durationMs !== exports.PET_BIN_MS
        || !model_js_1.CATEGORIES.includes(b.channel) || typeof b.waiting !== 'boolean'
        || !Array.isArray(b.agentIds) || b.agentIds.length > 250_000 || b.agentIds.some(id => typeof id !== 'string' || !id || id.length > 4096)
        || !Number.isSafeInteger(b.errors) || b.errors < 0 || b.errors > 250_000
        || !Array.isArray(b.onsets) || b.onsets.length !== 13 || b.onsets.some(n => !Number.isSafeInteger(n) || n < 0 || n > 250_000)
        || !Array.isArray(b.activeMs) || b.activeMs.length !== 13 || b.activeMs.some(n => !Number.isFinite(n) || n < 0 || n > 100_000_000))
        throw new Error('Invalid version 1 pet bucket.');
}
function decodePetJSONL(text) {
    if (text.length > 64 * 1024 * 1024)
        throw new Error('Pet tape exceeds 64 MiB.');
    const rows = text.split(/\r?\n/).filter(line => line.trim()).map(line => JSON.parse(line));
    if (rows.length > 216_000)
        throw new Error('Pet tape exceeds 24 hours.');
    return rows.map((row, i) => { validatePetBucket(row); if (row.sequence !== i)
        throw new Error('Non-contiguous pet tape.'); return row; });
}
/** A live file must advance before its contents count as a new observation.
 * Existing bytes, duplicate samples and a restarted sequence establish a
 * baseline; they never replay an old onset or human request. Drivers supply a
 * bounded tail and reset this cursor after suspension or a new attachment. */
class PetLiveTape {
    sequence;
    reset() { this.sequence = undefined; }
    readTail(text) {

View on GitHub (pinned to 73e0f67d83)