Hmbown/CodeWhale · error · Error
Signal duration must be finite and nonnegative.
Error message
Signal duration must be finite and nonnegative.
What it means
buildPyramid() derives the signal duration from the requestedDuration argument and the events' start/end/error-onset times, then requires the result to be a finite, non-negative number before computing bin widths. It throws when the effective duration is NaN, Infinity, or negative — usually because requestedDuration was invalid or some event carries non-finite/negative times.
Solutions
- Validate every event's startTime/endTime are finite and non-negative before calling buildPyramid (see its own 'Invalid interval' guard).
- Pass an explicit valid requestedDuration instead of relying on event-derived duration.
- Normalize open-ended spans to finite endTimes (e.g. use startTime or a cap) before compiling.
- Re-run importTrace() on raw data to guarantee event-v1 shapes with finite times.
Example fix
// before buildPyramid(events, requestedDuration); // requestedDuration = NaN // after const duration = Number.isFinite(requestedDuration) && requestedDuration >= 0 ? requestedDuration : Math.max(0, ...events.map(e => e.endTime)); buildPyramid(events, duration);
Defensive patterns
Strategy: type-guard
Validate before calling
const finiteNonNeg = (n) => typeof n === 'number' && Number.isFinite(n) && n >= 0;
if (!finiteNonNeg(requestedDuration)) {
requestedDuration = Math.max(0, ...events.map(e => e.endTime ?? 0));
} Type guard
const hasFiniteTimes = (e) => Number.isFinite(e.startTime) && Number.isFinite(e.endTime) && e.startTime >= 0 && e.endTime >= e.startTime;
Try / catch
try {
return buildPyramid(events, requestedDuration, maxBins);
} catch (e) {
if (e.message === 'Signal duration must be finite and nonnegative.') {
return buildPyramid(events, 1, maxBins);
}
throw e;
} Prevention
- Never represent open-ended spans with endTime = Infinity — use finite caps
- Run all data through importTrace so timestamps are normalized
- Guard against clock skew producing negative durations when subtracting origins
When it happens
Trigger: Passing requestedDuration = NaN/undefined where the events array is also empty or itself contains NaN times; an event with endTime = Infinity (never-closed span leaking through) or negative startTime; Math.max over mixed garbage yielding NaN (e.g. one event has startTime undefined so Math.max returns NaN).
Common situations: Open-ended spans stored with endTime = Infinity instead of the openEnded flag; a corrupted import leaving undefined timestamps; passing a negative requested duration computed from clock skew; compiling before importTrace normalization.
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
- Choose an appearance file smaller than 4 KiB.
- invalid_container
- Invalid event-v1 pet input. Import through importTrace…
- Invalid failure observation time.
- invalid_host
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/2a10e707e07f1d1c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/pet_watch/pet-native.js:1318
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;
fine.onsets[at + a]++;
fine.cost[at + a] += e.cost ?? 0;
if (e.status === 'error')
fine.errors[at + Math.floor((0, model_js_1.errorOnsetOf)(e) / binMs)]++;
const d = e.endTime - e.startTime, tokens = e.outputTokens ?? 0;View on GitHub (pinned to 73e0f67d83)