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 its signal duration from the requestedDuration argument or the maximum endTime/startTime/error onset across events. If that resolved duration is not a finite nonnegative number (NaN/Infinity from bad event timestamps or a bad requestedDuration), the pyramid geometry cannot be computed and this error is thrown.

Solutions

  1. Ensure all event startTime/endTime values are finite nonnegative numbers (errorOnsetOf included for error-status events).
  2. Pass a finite, nonnegative requestedDuration computed at the call site.
  3. Sanitize events before the call: replace open-ended/Infinity endTimes with a concrete value like startTime + 1000.
  4. Run events through importTrace, which validates the same invariants (see the event-v1 error).

Example fix

// before
buildPyramid(events, requestedDuration);
// after
const safe = events.map(e => ({ ...e, endTime: Number.isFinite(e.endTime) ? e.endTime : e.startTime + 1000 }));
buildPyramid(safe, Math.max(0, requestedDuration ?? 1));
Defensive patterns

Strategy: validation

Validate before calling

const finite = v => Number.isFinite(v) && v >= 0;
if (requestedDuration !== undefined && !finite(requestedDuration)) throw new TypeError('bad duration');
if (events.some(e => !finite(e.startTime) || !finite(e.endTime))) sanitizeEvents();

Try / catch

try { buildPyramid(events, d, bins) } catch (err) { if (err.message.includes('Signal duration')) return buildPyramid(sanitize(events), d, bins); throw err; }

Prevention

When it happens

Trigger: Passing a requestedDuration that is NaN/Infinity/negative, or events with non-finite or negative endTime/startTime/errorOnset values that contaminate the Math.max scan.

Common situations: Open-ended events with endTime = Infinity, timestamps parsed from malformed strings, or computing requestedDuration from a subtraction that yields NaN.

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@433685b202 (2026-09-15). Data as JSON: /api/errors/bca972e1d1011356. Report an issue: GitHub.

Appendix: source

Thrown at pet/ios/Resources/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 433685b202)