An API returning {"0": {...}, "1": {...}} instead of an array, because one filter had unset an element.
$rows = array_filter($rows, fn (Row $r) => $r->visible);
// keys are now 0, 2, 3 — not a list
json_encode($rows); // {"0":...,"2":...,"3":...}
// the guard, and the fix
if (! array_is_list($rows)) {
$rows = array_values($rows);
}
// or, in a test
self::assertTrue(array_is_list($payload['data']));
This has been a PHP API design hazard since JSON encoding existed, and array_is_list() makes the check explicit rather than a comparison against range(). Asserting it in the contract test for every collection endpoint is cheap and catches the case where a filter is added later — which is exactly how this one appeared, four years after the endpoint was written.