Apache AGE version
Observed on Docker image:
docker pull apache/age:latest
Pulled: 2026-07-09
Apache AGE: PostgreSQL 18.1
Endpoint:
postgres://127.0.0.1:5432
How are you accessing AGE
psql and Python psycopg2 driver
Environment
-
Host OS: Linux 5.4.0-216-generic
-
Deployment: Docker apache/age:latest
-
Query interface: psql and psycopg2
-
Query language: Cypher via ag_catalog.cypher
-
Configuration: default AGE on PostgreSQL 18, no extensions beyond AGE
-
Differential comparison targets:
- Neo4j
2026.05.0
- PostgreSQL native arithmetic
Description
AGE Cypher integer arithmetic silently wraps around on 64-bit overflow instead of failing the query.
For example:
SELECT * FROM cypher('test_graph', $$
RETURN 9223372036854775807 + 1 AS r
$$) AS (r agtype);
AGE returns:
r
---------------------
-9223372036854775808
This is a two's-complement wraparound from INT64_MAX to INT64_MIN.
The mathematical result is outside the signed 64-bit integer range, so the query should fail instead of returning another valid-looking integer value.
PostgreSQL native arithmetic rejects the same operation with bigint out of range, and Neo4j also rejects the equivalent Cypher expression with an arithmetic overflow error.
Setup
LOAD 'age';
SET search_path = ag_catalog, '$user', public;
SELECT * FROM ag_catalog.create_graph('test_graph');
Minimal reproduction
SELECT * FROM cypher('test_graph', $$
RETURN 9223372036854775807 + 1 AS r
$$) AS (r agtype);
Expected behavior
The query should fail with an integer overflow error.
PostgreSQL native arithmetic:
SELECT 9223372036854775807::bigint + 1::bigint;
returns:
ERROR: bigint out of range
Neo4j 2026.05.0 also rejects:
RETURN 9223372036854775807 + 1 AS r;
with an arithmetic overflow/client error.
Actual behavior
AGE returns a wrapped value:
r
---------------------
-9223372036854775808
No error or warning is reported.
Additional affected expressions
SELECT * FROM cypher('test_graph', $$
RETURN 9223372036854775807 * 2 AS r
$$) AS (r agtype);
AGE returns:
Expected: overflow error.
SELECT * FROM cypher('test_graph', $$
RETURN -9223372036854775808 - 1 AS r
$$) AS (r agtype);
AGE returns:
Expected: overflow error.
Control query
Arithmetic within range works correctly:
SELECT * FROM cypher('test_graph', $$
RETURN 1 + 1 AS r
$$) AS (r agtype);
AGE returns:
Impact: silent wrong results
The overflowed value participates in further query evaluation.
SELECT * FROM cypher('test_graph', $$
RETURN 9223372036854775807 + 1 > 0 AS r
$$) AS (r agtype);
AGE returns:
This result is derived from the wrapped negative value, not from the mathematical result of the expression.
A write context can also persist the wrapped value:
SELECT * FROM cypher('test_graph', $$
CREATE (:Overflow {v: 9223372036854775807 + 1})
RETURN 1 AS ok
$$) AS (ok agtype);
SELECT * FROM cypher('test_graph', $$
MATCH (n:Overflow)
RETURN n.v AS v
$$) AS (v agtype);
AGE returns:
Expected: the write query should fail before persisting an overflowed value.
Cross-engine comparison
| Engine |
MAX_INT + 1 |
MAX_INT * 2 |
MIN_INT - 1 |
Neo4j 2026.05.0 |
ArithmeticError |
ArithmeticError |
ArithmeticError |
PostgreSQL native bigint |
ERROR: bigint out of range |
ERROR: bigint out of range |
ERROR: bigint out of range |
| Apache AGE Cypher |
-9223372036854775808 |
-2 |
9223372036854775807 |
Why this looks like a bug
AGE documents agtype integer as a 64-bit field with the signed 64-bit range:
-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
and states that attempts to store values outside this range result in an error.
The tested Cypher expressions produce mathematical results outside that range. Instead of rejecting them, AGE returns wrapped in-range values. This behavior is consistent with unchecked int64 arithmetic.
Summary
64-bit integer arithmetic overflow should fail the query. Silently wrapping the result changes arithmetic semantics, can produce wrong predicates, and can persist incorrect property values.
Apache AGE version
Observed on Docker image:
How are you accessing AGE
psql and Python
psycopg2driverEnvironment
Host OS: Linux
5.4.0-216-genericDeployment: Docker
apache/age:latestQuery interface: psql and psycopg2
Query language: Cypher via
ag_catalog.cypherConfiguration: default AGE on PostgreSQL 18, no extensions beyond AGE
Differential comparison targets:
2026.05.0Description
AGE Cypher integer arithmetic silently wraps around on 64-bit overflow instead of failing the query.
For example:
AGE returns:
This is a two's-complement wraparound from
INT64_MAXtoINT64_MIN.The mathematical result is outside the signed 64-bit integer range, so the query should fail instead of returning another valid-looking integer value.
PostgreSQL native arithmetic rejects the same operation with
bigint out of range, and Neo4j also rejects the equivalent Cypher expression with an arithmetic overflow error.Setup
Minimal reproduction
Expected behavior
The query should fail with an integer overflow error.
PostgreSQL native arithmetic:
returns:
Neo4j
2026.05.0also rejects:with an arithmetic overflow/client error.
Actual behavior
AGE returns a wrapped value:
No error or warning is reported.
Additional affected expressions
AGE returns:
Expected: overflow error.
AGE returns:
Expected: overflow error.
Control query
Arithmetic within range works correctly:
AGE returns:
Impact: silent wrong results
The overflowed value participates in further query evaluation.
AGE returns:
This result is derived from the wrapped negative value, not from the mathematical result of the expression.
A write context can also persist the wrapped value:
AGE returns:
Expected: the write query should fail before persisting an overflowed value.
Cross-engine comparison
MAX_INT + 1MAX_INT * 2MIN_INT - 12026.05.0bigintERROR: bigint out of rangeERROR: bigint out of rangeERROR: bigint out of range-9223372036854775808-29223372036854775807Why this looks like a bug
AGE documents
agtypeinteger as a 64-bit field with the signed 64-bit range:and states that attempts to store values outside this range result in an error.
The tested Cypher expressions produce mathematical results outside that range. Instead of rejecting them, AGE returns wrapped in-range values. This behavior is consistent with unchecked
int64arithmetic.Summary
64-bit integer arithmetic overflow should fail the query. Silently wrapping the result changes arithmetic semantics, can produce wrong predicates, and can persist incorrect property values.