Skip to content

Intermittent build failure: off-by-one in shuffle adds undefined to the partner list #9321

Closed

Description

@bmuenzenmeyer

Summary

An off-by-one in shuffle can put undefined in the weighted partner list, which fails the build while prerendering /en:

Error occurred prerendering page "/en".
TypeError: Cannot read properties of undefined (reading 'id')
    at components/Common/Partners/index.tsx:35:37

The shuffle seed changes every 5 minutes, so the failure depends on when the build runs, not on the code being built. It looks like a random CI failure, and re-running the job clears it once the seed has moved on.

Cause

In apps/site/util/array.ts:

const randomValue = hash[hashIndex] / 255;
const j = Math.floor(randomValue * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];

When the hash byte is 255, randomValue is exactly 1, so j is i + 1. On the first pass of the loop, i is the last index, so j is one past the end of the array and undefined gets swapped in.

generatePartners keeps that undefined in its result, and renderSmallPartner then reads partner.id from it.

Occurrences

This has happened at least twice:

Date (UTC) Where Runner Error time Seed Job
2026-09-09 main at 69249e055 ubuntu-latest 20:01:26 5963280 job
2026-11-06 #9250 at 5f47eb60b windows-latest 17:17:26 5979951 job

For both, running the current shuffle with that commit's partner data gives undefined for the seed at the error time, and doesn't for the seed just before it. Neither commit touches this code, and the failures on two different operating systems show it isn't platform-specific.

These two came from searching the logs of the 100 most recent failed Build runs, so there may be others.

How often

generatePartners uses Math.floor(Date.now() / 300000) as the seed. With the current 20-entry weighted list, 83 of the 20,000 most recent seeds produce undefined (0.41%), which is one 5-minute window about every 20 hours. That matches the expected 1 in 256 chance of the byte being 255.

Reproduce

Run the current shuffle with a 20-entry array and seed 5979951. The result contains undefined.

Suggested fix

Divide by 256 so that j always stays in range:

-    const randomValue = hash[hashIndex] / 255;
+    const randomValue = hash[hashIndex] / 256;

util/__tests__ has no test file for array, so a regression test using one of the seeds above would be worthwhile.

Not yet checked

The homepage and download pages use sort="weight". Whether deployed pages can also hit this at request time, rather than only during a build, hasn't been investigated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions