abhigyanpatwari/GitNexus · error · Error

shard index must be in 1..${total}, got ${index}

Error message

shard index must be in 1..${total}, got ${index}

What it means

Thrown by shardFiles() when the 1-based 'index' (which shard to select) is not an integer, is less than 1, or exceeds 'total'. The function is called independently on each CI runner, so every runner must agree on the same (index, total) pair to produce a covering, non-overlapping partition.

Source

Thrown at gitnexus/scripts/cross-platform-shard.ts:116

 * than enough here, where the goal is only "no shard gets two monsters".
 *
 * Ties break on the file path so the partition is DETERMINISTIC: every shard
 * computes the same split independently, on a different machine, with no
 * coordination — which is what lets each runner select its own slice.
 *
 * Returns files in the input list's original order, not weight order, so failure
 * output and reruns stay readable.
 */
export function shardFiles(
  files: readonly string[],
  index: number,
  total: number,
): readonly string[] {
  if (!Number.isInteger(total) || total < 1) {
    throw new Error(`shard total must be a positive integer, got ${total}`);
  }
  if (!Number.isInteger(index) || index < 1 || index > total) {
    throw new Error(`shard index must be in 1..${total}, got ${index}`);
  }
  if (total === 1) return [...files];

  const byWeightDesc = [...files].sort((a, b) => {
    const diff = weightOf(b) - weightOf(a);
    return diff !== 0 ? diff : a.localeCompare(b);
  });

  const loads = Array.from({ length: total }, () => 0);
  const assigned = Array.from({ length: total }, () => new Set<string>());
  for (const file of byWeightDesc) {
    let lightest = 0;
    for (let i = 1; i < total; i++) {
      if (loads[i]! < loads[lightest]!) lightest = i;
    }
    assigned[lightest]!.add(file);
    loads[lightest]! += weightOf(file);
  }

View on GitHub (pinned to d540b00184)

Solutions

  1. Ensure index is 1-based and within [1, total]: if your source is zero-based, pass index0 + 1.
  2. Validate the pair together: if (!(index >= 1 && index <= total)) throw a clearer upstream error.
  3. Coerce from env: Math.min(total, Math.max(1, Math.floor(Number(process.env.SHARD_INDEX) || 1))).

Example fix

// before (zero-based matrix variable i)
const mine = shardFiles(files, i, total);

// after
const mine = shardFiles(files, i + 1, total);
Defensive patterns

Strategy: validation

Validate before calling

function safeIndex(index, total) {
  const i = Math.floor(Number(index));
  if (!Number.isInteger(i) || i < 1 || i > total) {
    throw new Error(`shard index ${index} out of range 1..${total}`);
  }
  return i;
}

Type guard

function isValidShardIndex(index: unknown, total: number): index is number {
  return typeof index === 'number' && Number.isInteger(index) && index >= 1 && index <= total;
}

Prevention

When it happens

Trigger: Calling shardFiles(files, 0, 3) (zero-based index mistake), shardFiles(files, 4, 3) (index exceeds total), shardFiles(files, 1.5, 3), or shardFiles(files, NaN, 3).

Common situations: Treating the shard index as zero-based when the API expects 1-based (the most common cause); a CI matrix that numbers shards 1..N but a job variable offset by one; reading the index from an env var that was never validated.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/8b028bc8ba66514e. Report an issue: GitHub.