videojs/video.js · error · Error

Failed to execute '${fnName}' on 'TimeRanges': The index pro

Error message

Failed to execute '${fnName}' on 'TimeRanges': The index provided (${index}) is non-numeric or out of bounds (0-${maxIndex}).

What it means

Thrown by the private rangeCheck helper guarding TimeRanges start(i)/end(i). It fires when the index is non-numeric, negative, or greater than length-1. This mirrors the native HTML5 TimeRanges spec error and is bound into every non-empty TimeRanges object returned by player.buffered/seekable/played.

Source

Thrown at src/js/utils/time.js:57

/**
 * Check if any of the time ranges are over the maximum index.
 *
 * @private
 * @param   {string} fnName
 *          The function name to use for logging
 *
 * @param   {number} index
 *          The index to check
 *
 * @param   {number} maxIndex
 *          The maximum possible index
 *
 * @throws  {Error} if the timeRanges provided are over the maxIndex
 */
function rangeCheck(fnName, index, maxIndex) {
  if (typeof index !== 'number' || index < 0 || index > maxIndex) {
    throw new Error(`Failed to execute '${fnName}' on 'TimeRanges': The index provided (${index}) is non-numeric or out of bounds (0-${maxIndex}).`);
  }
}

/**
 * Get the time for the specified index at the start or end
 * of a TimeRange object.
 *
 * @private
 * @param      {string} fnName
 *             The function name to use for logging
 *
 * @param      {string} valueIndex
 *             The property that should be used to get the time. should be
 *             'start' or 'end'
 *
 * @param      {Array} ranges
 *             An array of time ranges
 *

View on GitHub (pinned to c3a7e0e6d2)

Solutions

  1. Check timeRanges.length before indexing.
  2. Iterate with for (let i = 0; i < ranges.length; i++).
  3. Coalesce to a safe index: const idx = Math.min(i, ranges.length - 1).

Example fix

// before
const end = player.buffered().end(1);
// after
const b = player.buffered();
const end = b.length >= 2 ? b.end(1) : (b.length === 1 ? b.end(0) : 0);
Defensive patterns

Strategy: validation

Validate before calling

function rangeAt(ranges, fn, i = 0) {
  if (typeof i !== 'number' || i < 0 || i >= ranges.length) {
    throw new RangeError(`index ${i} out of bounds for length ${ranges.length}`);
  }
  return ranges[fn](i);
}

Type guard

function isValidRangeIndex(ranges, i) {
  return typeof i === 'number' && i >= 0 && i < ranges.length;
}

Try / catch

try {
  return ranges.start(i);
} catch (err) {
  if (/TimeRanges/.test(err.message) && /out of bounds|non-numeric/.test(err.message)) {
    return ranges.length ? ranges.start(ranges.length - 1) : 0;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling player.buffered().start(5) when fewer ranges exist; passing a string index; an off-by-one loop (i <= length instead of i < length); calling start()/end() with no index on a non-empty object (the deprecated default of 0 is tolerated).

Common situations: Looping over buffered/seekable ranges without checking .length; assuming exactly one buffered range for progressive downloads; computing progress as buffered().end(length-1) on a live/HLS stream where ranges shift.

Related errors


AI-assisted analysis of videojs/video.js@c3a7e0e6d2 (2026-08-13). Data as JSON: /api/errors/f9e201911ccfe510. Report an issue: GitHub.