Environment
ArcadeDB version: 26.5.1-SNAPSHOT (build 25ed565)
Cluster: 3-node Raft HA
Summary
The /api/v1/batch/{db} endpoint returns HTTP 500 with a NullPointerException after
successfully committing all vertices and edges. The response body reports:
{
"error": "Error on transaction commit",
"detail": "Cannot invoke \"com.arcadedb.database.Binary.toByteArray()\" because \"phase1.result\" is null",
"exception": "java.lang.NullPointerException"
}
However, SELECT count(*) confirms that all records were persisted correctly.
Steps to Reproduce
python reproduce_batch_npe.py
#!/usr/bin/env python3
import json
import requests
from requests.auth import HTTPBasicAuth
ARCADE_URL = "http://10.91.15.22:2480/api/v1"
DB = "batch_npe_repro"
USER = "root"
PASSWORD = "pass"
NUM_VERTICES = 500
NUM_EDGES = 500
session = requests.Session()
session.auth = HTTPBasicAuth(USER, PASSWORD)
def sql(statement):
r = session.post(
f"{ARCADE_URL}/command/{DB}",
json={"language": "sql", "command": statement},
timeout=30,
)
return r.status_code, r.json() if r.status_code == 200 else r.text
def create_database():
session.post(f"{ARCADE_URL}/server", json={"command": f"drop database {DB}"}, timeout=30)
r = session.post(f"{ARCADE_URL}/server", json={"command": f"create database {DB}"}, timeout=30)
if r.status_code != 200:
raise RuntimeError(f"Cannot create database: {r.status_code}")
def setup_schema():
sql("CREATE VERTEX TYPE TestNode IF NOT EXISTS")
sql("CREATE PROPERTY TestNode.node_id IF NOT EXISTS STRING")
sql("CREATE INDEX ON TestNode (node_id) UNIQUE")
sql("CREATE EDGE TYPE TestEdge IF NOT EXISTS")
def build_payload():
lines = []
for i in range(NUM_VERTICES):
lines.append(json.dumps({
"@type": "vertex", "@class": "TestNode", "@id": f"n{i}",
"node_id": f"n{i}", "label": f"Node {i}",
}))
for i in range(NUM_EDGES):
lines.append(json.dumps({
"@type": "edge", "@class": "TestEdge",
"@from": f"n{i}", "@to": f"n{(i + 1) % NUM_VERTICES}", "weight": i,
}))
return "\n".join(lines)
def send_batch(payload):
resp = session.post(
f"{ARCADE_URL}/batch/{DB}?batchSize=50000&commitEvery=50000",
data=payload.encode("utf-8"),
headers={"Content-Type": "application/x-ndjson"},
timeout=120,
)
return resp.status_code, resp.text
def verify():
_, v = sql("SELECT count(*) AS c FROM TestNode")
_, e = sql("SELECT count(*) AS c FROM TestEdge")
v_count = v.get("result", [{}])[0].get("c", 0) if isinstance(v, dict) else -1
e_count = e.get("result", [{}])[0].get("c", 0) if isinstance(e, dict) else -1
return v_count, e_count
def main():
create_database()
setup_schema()
status, body = send_batch(build_payload())
v_count, e_count = verify()
if status == 500 and v_count == NUM_VERTICES and e_count == NUM_EDGES:
print(f"HTTP 500 but all data committed. vertices={v_count}/{NUM_VERTICES}, edges={e_count}/{NUM_EDGES}, response={body[:300]}")
elif status != 200:
print(f"HTTP {status} — vertices={v_count}, edges={e_count}, response={body[:300]}")
elif v_count != NUM_VERTICES or e_count != NUM_EDGES:
print(f"Count mismatch: vertices={v_count}/{NUM_VERTICES}, edges={e_count}/{NUM_EDGES}")
if __name__ == "__main__":
main()
Expected Behavior
The /batch endpoint should return HTTP 200 with accurate verticesCreated / edgesCreated
counts when the data is successfully committed.
Actual Behavior
HTTP 500 is returned with a NullPointerException on phase1.result. The data is committed
to disk, but the client receives an error response.
Environment
ArcadeDB version: 26.5.1-SNAPSHOT (build 25ed565)
Cluster: 3-node Raft HA
Summary
The
/api/v1/batch/{db}endpoint returns HTTP 500 with aNullPointerExceptionaftersuccessfully committing all vertices and edges. The response body reports:
{ "error": "Error on transaction commit", "detail": "Cannot invoke \"com.arcadedb.database.Binary.toByteArray()\" because \"phase1.result\" is null", "exception": "java.lang.NullPointerException" }However,
SELECT count(*)confirms that all records were persisted correctly.Steps to Reproduce
Expected Behavior
The
/batchendpoint should return HTTP 200 with accurateverticesCreated/edgesCreatedcounts when the data is successfully committed.
Actual Behavior
HTTP 500 is returned with a
NullPointerExceptiononphase1.result. The data is committedto disk, but the client receives an error response.