{"record":{"id":"0d1b44cbaebd4874","repo":"Hmbown/CodeWhale","slug":"maxbins-must-be-an-integer-in-16-1048576","errorCode":null,"errorMessage":"maxBins must be an integer in [16, 1048576].","messagePattern":"maxBins must be an integer in \\[16, 1048576\\]\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":1313,"sourceCode":"exports.chooseLevel = chooseLevel;\nexports.binValue = binValue;\nexports.intensity = intensity;\nexports.totals = totals;\nexports.onsetSeries = onsetSeries;\nexports.autocorrelation = autocorrelation;\nexports.periodogram = periodogram;\nexports.unionDuration = unionDuration;\nconst model_js_1 = require(\"./model.js\");\nfunction emptyLevel(length, binMs) {\n    const n = model_js_1.CATEGORIES.length * length;\n    return { binMs, length, onsets: new Float64Array(n), activeMs: new Float64Array(n),\n        outputTokens: new Float64Array(n), cost: new Float64Array(n), errors: new Float64Array(n), peak: new Float64Array(n) };\n}\nconst FIELDS = ['onsets', 'activeMs', 'outputTokens', 'cost', 'errors'];\n/** O(events + channels × bins), including long intervals. No span-length inner loop. */\nfunction buildPyramid(events, requestedDuration, maxBins = 16_384) {\n    if (!Number.isInteger(maxBins) || maxBins < 16 || maxBins > 1_048_576)\n        throw new Error('maxBins must be an integer in [16, 1048576].');\n    let duration = requestedDuration ?? 1;\n    for (const e of events)\n        duration = Math.max(duration, e.endTime, e.startTime, e.status === 'error' ? (0, model_js_1.errorOnsetOf)(e) : 0);\n    if (!Number.isFinite(duration) || duration < 0)\n        throw new Error('Signal duration must be finite and nonnegative.');\n    duration = Math.max(1, duration);\n    const binMs = 2 ** Math.ceil(Math.log2(Math.max(1, duration / (maxBins - 1))));\n    const length = Math.floor(duration / binMs) + 1, fine = emptyLevel(length, binMs);\n    const stride = length + 1;\n    const activeDiff = new Float64Array(model_js_1.CATEGORIES.length * stride), tokenDiff = new Float64Array(model_js_1.CATEGORIES.length * stride);\n    for (const e of events) {\n        if (!Number.isFinite(e.startTime) || !Number.isFinite(e.endTime) || e.startTime < 0 || e.endTime < e.startTime)\n            throw new Error(`Invalid interval for ${e.id}.`);\n        const channel = model_js_1.CATEGORIES.indexOf(e.category);\n        if (channel < 0)\n            throw new Error(`Unknown category for ${e.id}.`);\n        const a = Math.floor(e.startTime / binMs), b = Math.floor(e.endTime / binMs);\n        const at = channel * length, diff = channel * stride;","sourceCodeStart":1295,"sourceCodeEnd":1331,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L1295-L1331","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nbuildPyramid(events, duration, userBins); // userBins = 4\n// after\nconst maxBins = Math.min(1_048_576, Math.max(16, Math.round(userBins)));\nbuildPyramid(events, duration, maxBins);","handlingStrategy":"validation","validationCode":"const clampBins = (n) =>\n  Number.isFinite(n) ? Math.min(1_048_576, Math.max(16, Math.round(n))) : 16_384;\nbuildPyramid(events, duration, clampBins(opts.maxBins));","typeGuard":"const isValidMaxBins = (v) => Number.isInteger(v) && v >= 16 && v <= 1_048_576;","tryCatchPattern":"try {\n  return buildPyramid(events, duration, maxBins);\n} catch (e) {\n  if (e.message.startsWith('maxBins must be')) {\n    return buildPyramid(events, duration); // default 16384\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["parameter-validation","javascript"],"backgroundTag":"invalid-argument-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}