Hmbown/CodeWhale · error · Error
maxBins must be an integer in [16, 1048576].
Error message
maxBins must be an integer in [16, 1048576].
What it means
buildPyramid() validates its maxBins option, which sets the resolution of the finest pyramid level. It must be an integer between 16 and 1,048,576 inclusive. The library throws this error when maxBins is fractional, not a number (NaN/undefined coerced oddly is allowed only via the default), or outside that range.
Solutions
- Clamp and round the option before calling: maxBins = Math.min(1_048_576, Math.max(16, Math.round(raw))).
- Omit maxBins to use the default of 16384 if a custom value is not actually needed.
- Check argument order — make sure a duration or other number is not being passed as maxBins.
- If the option comes from config, validate/parse it at load time and reject non-integer strings.
Example fix
// before buildPyramid(events, duration, userBins); // userBins = 4 // after const maxBins = Math.min(1_048_576, Math.max(16, Math.round(userBins))); buildPyramid(events, duration, maxBins);
Defensive patterns
Strategy: validation
Validate before calling
const clampBins = (n) => Number.isFinite(n) ? Math.min(1_048_576, Math.max(16, Math.round(n))) : 16_384; buildPyramid(events, duration, clampBins(opts.maxBins));
Type guard
const isValidMaxBins = (v) => Number.isInteger(v) && v >= 16 && v <= 1_048_576;
Try / catch
try {
return buildPyramid(events, duration, maxBins);
} catch (e) {
if (e.message.startsWith('maxBins must be')) {
return buildPyramid(events, duration); // default 16384
}
throw e;
} Prevention
- Round slider/percent-derived bin counts with Math.round before use
- Clamp user config values into [16, 1048576] at load time
- Double-check argument order so other numbers don't land in the maxBins slot
When it happens
Trigger: Calling buildPyramid(events, duration, maxBins) with maxBins = 0, 1, 8 (below the floor), 2_000_000 (above the cap), a float like 100.5, or NaN from a failed option parse.
Common situations: A UI slider producing fractional values without Math.round; config where the user set an unreasonably small or huge bin count; a constructor passing the wrong argument into the maxBins slot (e.g. duration passed twice).
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
- Invalid first pet bucket.
- Invalid pet clock origin.
- Archive the legacy recording before accepting more…
- Choose an appearance file smaller than 4 KiB.
- invalid_container
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/0d1b44cbaebd4874.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/pet_watch/pet-native.js:1313
exports.chooseLevel = chooseLevel;
exports.binValue = binValue;
exports.intensity = intensity;
exports.totals = totals;
exports.onsetSeries = onsetSeries;
exports.autocorrelation = autocorrelation;
exports.periodogram = periodogram;
exports.unionDuration = unionDuration;
const model_js_1 = require("./model.js");
function emptyLevel(length, binMs) {
const n = model_js_1.CATEGORIES.length * length;
return { binMs, length, onsets: new Float64Array(n), activeMs: new Float64Array(n),
outputTokens: new Float64Array(n), cost: new Float64Array(n), errors: new Float64Array(n), peak: new Float64Array(n) };
}
const FIELDS = ['onsets', 'activeMs', 'outputTokens', 'cost', 'errors'];
/** O(events + channels × bins), including long intervals. No span-length inner loop. */
function buildPyramid(events, requestedDuration, maxBins = 16_384) {
if (!Number.isInteger(maxBins) || maxBins < 16 || maxBins > 1_048_576)
throw new Error('maxBins must be an integer in [16, 1048576].');
let duration = requestedDuration ?? 1;
for (const e of events)
duration = Math.max(duration, e.endTime, e.startTime, e.status === 'error' ? (0, model_js_1.errorOnsetOf)(e) : 0);
if (!Number.isFinite(duration) || duration < 0)
throw new Error('Signal duration must be finite and nonnegative.');
duration = Math.max(1, duration);
const binMs = 2 ** Math.ceil(Math.log2(Math.max(1, duration / (maxBins - 1))));
const length = Math.floor(duration / binMs) + 1, fine = emptyLevel(length, binMs);
const stride = length + 1;
const activeDiff = new Float64Array(model_js_1.CATEGORIES.length * stride), tokenDiff = new Float64Array(model_js_1.CATEGORIES.length * stride);
for (const e of events) {
if (!Number.isFinite(e.startTime) || !Number.isFinite(e.endTime) || e.startTime < 0 || e.endTime < e.startTime)
throw new Error(`Invalid interval for ${e.id}.`);
const channel = model_js_1.CATEGORIES.indexOf(e.category);
if (channel < 0)
throw new Error(`Unknown category for ${e.id}.`);
const a = Math.floor(e.startTime / binMs), b = Math.floor(e.endTime / binMs);
const at = channel * length, diff = channel * stride;View on GitHub (pinned to 73e0f67d83)