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

  1. Clamp and round the option before calling: maxBins = Math.min(1_048_576, Math.max(16, Math.round(raw))).
  2. Omit maxBins to use the default of 16384 if a custom value is not actually needed.
  3. Check argument order — make sure a duration or other number is not being passed as maxBins.
  4. 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

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


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)