range() with 2^31 or more elements: size() returns 0 and property storage silently truncates the list to its prefix
Neo4j Version: neo4j:2026.07.1 (Docker)
Installation Method: Docker
API: Cypher (Bolt / cypher-shell)
Steps to reproduce
size()wraps to 0 at exactly 2^31 elements:
RETURN size(range(0, 2147483647, 1)) AS s // -> 0
RETURN size(range(0, 2147483648, 1)) AS s // -> 2147483649 (control: correct)- Storing such a range as a property silently truncates it:
CREATE (n {p: range(0, 4294967296, 1)}) RETURN n.p // -> [0]
CREATE (n {p: range(0, 4294967297, 1)}) RETURN n.p // -> [0, 1]- Control - lengths below 2^31 are rejected cleanly:
CREATE (n {p: range(0, 2147483648, 1)}) RETURN n.p
// 22N28: data exception - overflow error. The result of the operation 'range()' has caused an overflow.Expected behavior
A range of 2^31+ elements is not representable as a stored list; the engine already rejects sizes below 2^31 with a clean 22N28 overflow error, and it should do the same for every out-of-int-range size (or reject in range()) up front). size()` must report the actual element count.
Actual behavior
IntegralRangeListValue narrows its long size with a plain (int) cast. In size() (intSize(), line 88) the wrapped value for exactly 2^31 elements is 0. In the property-write path the (int) actualSize() cast at line 248 lands in the [0, 2^31) window for any size in [2^32, 2^32 + 2^31), bypassing the existing size < 0 guard: the value silently stored is the truncated prefix ([0], [0, 1], ...) instead of the range the user wrote - silent data corruption from a single CREATE. For sizes ≥ 2^32 + 2^30 the wrapped positive size survives the guard and the write path attempts to materialize the full list, failing with 51N36: out of memory, which makes a single property assignment a memory-exhaustion vector.
Source: neo4j/neo4j