796 words
4 minutes

JavaScript every Returns true for Empty Arrays: Validate Required Lists

2026-11-03
Frontend
JavaScript
/
Node.js
/
Troubleshooting
Contents

[].every(isValid) returns true. If a form requires at least one name, checking only names.every(isValid) lets an empty list pass. Add a separate nonempty requirement. If sparse arrays are possible, also decide whether every position must contain an own entry: a positive length alone does not establish that.

For a dense array you control, names.length > 0 && names.every(isValid) expresses “at least one, and all valid.” For a required list that must reject missing positions, use the explicit position check below.

Reproduce the validation gap#

The ECMAScript algorithm returns false when a visited callback fails and true after traversal finishes without a failure. Empty input reaches that final return immediately. MDN documents the empty-array and sparse-slot behavior.

The following fixture separates three questions: did every visited value pass, did every required position exist, and was the list nonempty? Its output and assertions were executed with Node.js 24.13.0 on macOS on November 3, 2026. Save it as required-names.mjs and run node required-names.mjs.

import assert from 'node:assert/strict';
const valid = value => typeof value === 'string' && value.trim().length > 0;
function requiredNames(values) {
if (!Array.isArray(values) || values.length === 0) return false;
for (let i = 0; i < values.length; i++) {
if (!Object.hasOwn(values, i) || !valid(values[i])) return false;
}
return true;
}
const cases = [
['empty', [], true, false, []],
['holes', new Array(2), true, false, []],
['one hole', ['Ada', , 'Lin'], true, false, [0, 2]],
['undefined', [undefined], false, false, [0]],
['blank', [' '], false, false, [0]],
['valid', ['Ada', 'Lin'], true, true, [0, 1]],
['invalid first', ['', 'Lin'], false, false, [0]],
];
for (const [label, input, expectedEvery, expectedRequired, indices] of cases) {
const visited = [];
const all = input.every((value, index) => {
visited.push(index);
return valid(value);
});
const required = requiredNames(input);
assert.equal(all, expectedEvery, label);
assert.equal(required, expectedRequired, label);
assert.deepEqual(visited, indices, label);
console.log(`${label}: every=${all} required=${required} visited=[${visited}]`);
}
for (const input of [null, undefined, 'Ada', { 0: 'Ada', length: 1 }]) {
assert.equal(requiredNames(input), false);
}
const inherited = new Array(1);
Object.setPrototypeOf(inherited, { 0: 'Ada', every: Array.prototype.every });
assert.equal(inherited.every(valid), true);
assert.equal(requiredNames(inherited), false);
console.log('non-arrays and inherited-only entries rejected');

Expected output:

empty: every=true required=false visited=[]
holes: every=true required=false visited=[]
one hole: every=true required=false visited=[0,2]
undefined: every=false required=false visited=[0]
blank: every=false required=false visited=[0]
valid: every=true required=true visited=[0,1]
invalid first: every=false required=false visited=[0]
non-arrays and inherited-only entries rejected

The holes row has length 2 but no entries. Its predicate never runs, so adding only a length guard would still accept it. The mixed row shows a less obvious failure: valid values on either side of a missing position make every() succeed while the required-list check rejects the absent entry.

An explicit undefined is different. The callback runs at position 0 and rejects the value. Avoid diagnosing all three cases as “empty”: the callback trace tells you whether the validator saw an invalid value or saw no value at all.

Choose the list contract before the predicate#

Input contractCheckWhat it accepts
Optional list; only visited values must be validvalues.every(valid)Empty arrays and arrays of holes pass
Required dense array from a controlled producervalues.length > 0 && values.every(valid)Rejects empty arrays; assumes density
Required array with an own valid value at every positionrequiredNames(values)Rejects empty, sparse, inherited-only, and invalid entries

The fixture’s valid predicate accepts nonblank strings. It uses trim() for the check without rewriting the original string. Replace that predicate with the field’s actual rule; an existence check alone does not establish a usable value. The own-property guide explains why presence and value validation are separate decisions.

requiredNames first rejects non-arrays, then rejects zero length, then checks each numeric position. Object.hasOwn makes the ownership policy explicit. The final inherited-entry assertion constructs an array whose missing own entry can be read from its prototype. The ordinary every call accepts that value; the required-list function rejects it. This is a local prototype on one fixture object, without modifying the global array prototype.

Keep validation synchronous and stable#

The callback trace also shows short-circuiting: after the first invalid string, later entries are not visited. Put diagnostics in a separate pass if your form needs every error at once. A predicate with logging or other side effects should not assume it will run once per array position.

These examples validate ordinary arrays of strings without mutation during validation. They do not establish a contract for proxies, getters with side effects, array subclasses, or values modified concurrently by application code. The explicit loop also reads the current length on each iteration; do not let a custom predicate mutate the input while checking it.

Keep the predicate synchronous. An async callback returns a promise, which is a different value from its eventual boolean result. Resolve asynchronous checks before aggregating their booleans; changing the nonempty guard cannot make an async predicate synchronous.

For a required list, retain assertions for empty input, a hole, an explicit invalid value, and a valid nonempty list. Those four cases keep list membership requirements separate from per-value rules as the form evolves.

References:

JavaScript every Returns true for Empty Arrays: Validate Required Lists
https://laplusda.com/en/posts/javascript-every-empty-array-validation/
Author
Zero
Published at
2026-11-03
License
CC BY-NC-SA 4.0