Hmbown/CodeWhale · error · Error
Invalid version 1 pet bucket.
Error message
Invalid version 1 pet bucket.
What it means
validatePetBucket enforces the version-1 PetBucket schema: exact simTimeMs/durationMs alignment to PET_BIN_MS, a known channel Category, boolean waiting, bounded agentIds (strings ≤4096 chars, ≤250k), safe-integer errors, and 13-element onsets/activeMs arrays within bounds. Any violation throws this error, so corrupt or foreign rows never enter telemetry.
Solutions
- Regenerate the offending row so every field matches the v1 schema (bin-aligned simTimeMs/durationMs, 13-length onsets and activeMs)
- Check the writer's schema version — upgrade the reader if the data is intentionally v2
- Sanitize ids to ≤4096 chars and counts to within the documented bounds at ingestion
- Skip/quarantine the invalid line instead of feeding it to decodePetJSONL/readTail
Example fix
// before
buckets.push({ simTimeMs: Date.now() % PET_BIN_MS, durationMs: 1234, ... });
// after
buckets.push({ simTimeMs: sequence * PET_BIN_MS, durationMs: PET_BIN_MS, onsets: new Array(13).fill(0), activeMs: new Array(13).fill(0), ... }); Defensive patterns
Strategy: validation
Validate before calling
function isLikelyValidBucket(b: any): boolean {
return b && b.simTimeMs === b.sequence * PET_BIN_MS && b.durationMs === PET_BIN_MS
&& 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
function isPetBucket(v: unknown): v is PetBucket {
const b = v as PetBucket;
return !!b && typeof b.sequence === 'number' && typeof b.simTimeMs === 'number'
&& Array.isArray(b.onsets) && b.onsets.length === 13
&& Array.isArray(b.activeMs) && b.activeMs.length === 13
&& typeof b.waiting === 'boolean' && Array.isArray(b.agentIds);
} Try / catch
try {
validatePetBucket(row);
} catch (e) {
if (e.message === 'Invalid version 1 pet bucket.') {
quarantine.push({ line: rawLine, reason: e.message }); // skip bad row, keep going
} else throw e;
} Prevention
- Keep writer and reader schema versions in lockstep
- Bin-align simTimeMs and set durationMs = PET_BIN_MS at the writer
- Always emit 13-element onsets/activeMs arrays
- Bound agent id length (≤4096) and counts at ingestion
When it happens
Trigger: decodePetJSONL, readTail, the telemetry store constructor, or acceptTelemetry receiving a parsed JSON row that fails any of the field checks — wrong bin alignment, unknown channel string, onsets.length !== 13, negative errors, oversized id strings, etc.
Common situations: A telemetry writer upgraded to a version-2 schema while the reader still expects v1; manually generated or synthetic JSONL rows with wrong field shapes; truncated lines that parse as JSON but lack fields; clock skew producing simTimeMs !== sequence*PET_BIN_MS.
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
- Invalid Engine pet metadata fields.
- Invalid pet state.
- Invalid version 1 pet bucket.
- Codewhale terminal receipt contained a non-scalar field
- Duplicate .
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/d08112608fde8b99.
Report an issue: GitHub.
Appendix: source
Thrown at pet/src/core/pet-telemetry.ts:30
durationMs: number;
onsets: number[];
activeMs: number[];
errors: number;
agentIds: string[];
waiting: boolean;
}
export function validatePetBucket(value: unknown): asserts value is PetBucket {
validatePetState(value);
const b = value as PetBucket;
if (!b || typeof b !== 'object' || b.version !== 1 || !Number.isSafeInteger(b.sequence) || b.sequence < 0 || b.sequence > PET_MAX_SECONDS * 2.5
|| b.simTimeMs !== b.sequence * PET_BIN_MS || b.durationMs !== PET_BIN_MS
|| !CATEGORIES.includes(b.channel as Category) || 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.');
}
export function decodePetJSONL(text: string): PetBucket[] {
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) as unknown);
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. */
export class PetLiveTape {
private sequence: number | undefined;
reset(): void { this.sequence = undefined; }
readTail(text: string): PetBucket | undefined {
if (!text) { this.reset(); return; }View on GitHub (pinned to 433685b202)