ankane/pghero · error · Error

noUiSlider: invalid handle number, got: {handleNumber}

Error message

noUiSlider: invalid handle number, got: {handleNumber}

What it means

valueSetHandle() coerces the handle number with Number() and requires 0 <= handleNumber < scope_HandleNumbers.length (the number of handles created from the start option). API calls that address a single handle - chiefly noUiSlider.setHandle(handleNumber, value) - throw this Error when the index does not exist, including the NaN case from non-numeric input.

Source

Thrown at app/assets/javascripts/pghero/nouislider.js:2087

            setZindex();
            scope_HandleNumbers.forEach(function (handleNumber) {
                fireEvent("update", handleNumber);
                // Fire the event only for handles that received a new value, as per #579
                if (values[handleNumber] !== null && fireSetEvent) {
                    fireEvent("set", handleNumber);
                }
            });
        }
        // Reset slider to initial values
        function valueReset(fireSetEvent) {
            valueSet(options.start, fireSetEvent);
        }
        // Set value for a single handle
        function valueSetHandle(handleNumber, value, fireSetEvent, exactInput) {
            // Ensure numeric input
            handleNumber = Number(handleNumber);
            if (!(handleNumber >= 0 && handleNumber < scope_HandleNumbers.length)) {
                throw new Error("noUiSlider: invalid handle number, got: " + handleNumber);
            }
            // Look both backward and forward, since we don't want this handle to "push" other handles (#960);
            // The exactInput argument can be used to ignore slider stepping (#436)
            setHandle(handleNumber, resolveToValue(value, handleNumber), true, true, exactInput);
            fireEvent("update", handleNumber);
            if (fireSetEvent) {
                fireEvent("set", handleNumber);
            }
        }
        // Get the slider value.
        function valueGet(unencoded) {
            if (unencoded === void 0) { unencoded = false; }
            if (unencoded) {
                // return a copy of the raw values
                return scope_Values.length === 1 ? scope_Values[0] : scope_Values.slice(0);
            }
            var values = scope_Values.map(options.format.to);
            // If only one handle is used, return a single value.

View on GitHub (pinned to 7edb57986f)

Solutions

  1. Check the live handle count before setting: slider.noUiSlider.get().length is the number of handles
  2. Use set() with an array matching the start configuration instead of setHandle when targeting all handles
  3. Make the handle count explicit in one place and derive both start and any setHandle indices from it

Example fix

// before - slider has one handle but index 1 requested
slider.noUiSlider.setHandle(1, 50);

// after - guard against the handle count
if (index < slider.noUiSlider.get().length) {
  slider.noUiSlider.setHandle(index, 50);
}
Defensive patterns

Strategy: validation

Validate before calling

const handleCount = slider.noUiSlider.get().length; // works for 1..n handles
if (handleNumber >= 0 && handleNumber < handleCount) {
  slider.noUiSlider.setHandle(handleNumber, value);
}

Prevention

When it happens

Trigger: A slider created with start: [50] (one handle) followed by slider.noUiSlider.setHandle(1, 80); an index computed from data attributes or loops that goes past handle count - 1; passing undefined (Number(undefined) is NaN, which fails the range check).

Common situations: Handle count varies with configuration (start array length changes) while calling code hardcodes indices; off-by-one loops over handles; saved UI state (per-handle positions) replayed onto a slider that now has fewer handles.

Related errors


AI-assisted analysis of ankane/pghero@7edb57986f (2026-08-21). Data as JSON: /api/errors/616da10f55fb495b. Report an issue: GitHub.