Skip to content

Nodes deleted earlier in the same query may still match later #4185

@Silence6666668

Description

@Silence6666668

ArcadeDB version
Observed on Docker images:

  • arcadedata/arcadedb:26.3.2
  • arcadedata/arcadedb:26.4.1-SNAPSHOT
  • arcadedata/arcadedb:26.4.2

Environment

  • Host OS: Windows 10
  • Architecture: x86_64
  • Deployment: Docker
  • ArcadeDB endpoint: HTTP /api/v1/command/arcade
  • Request mode matches ArcadeDB Studio:
    • language: opencypher
    • serializer: studio
  • Differential comparison target: Neo4j Docker neo4j:latest

Describe the bug
ArcadeDB may continue to match nodes that were deleted earlier in the same query.

In the minimized repro below, the query deletes the end node of each relationship, deletes the relationship itself, and then performs a later MATCH (n:Node).

Neo4j only sees the surviving node A.
ArcadeDB still sees both A and the already-deleted node B.

So this is not just an orphan-check bug.
The deleted node itself remains visible to a later scan inside the same query.

To Reproduce

Setup:

CREATE (a:Node {name:'A'})-[:REL]->(b:Node {name:'B'});

Query:

MATCH p = ()-[*]->()
WITH relationships(p) AS rels
FOREACH (r IN rels | DELETE endNode(r) DELETE r)
MATCH (n:Node)
RETURN n.name AS name
ORDER BY name;

Expected behavior
After deleting B and the REL edge, only A should still exist.

Observed Neo4j result:

A

ArcadeDB should return the same single row.

Actual behavior
Observed ArcadeDB result on all tested versions:

A
B

So the node deleted through DELETE endNode(r) is still visible to the later MATCH.

Control case
If there is no later match, the deletion query itself completes normally:

MATCH p = ()-[*]->()
WITH relationships(p) AS rels
FOREACH (r IN rels | DELETE endNode(r) DELETE r)
RETURN 1 AS x;

Observed result on Neo4j and all tested ArcadeDB versions:

1

So the problem is not that DELETE endNode(r) is rejected.
The issue is that the later query stage still sees nodes that should already be gone.

Orphan-check variant
The same root issue also appears if the later stage only asks for isolated nodes:

MATCH p = ()-[*]->()
WITH relationships(p) AS rels
FOREACH (r IN rels | DELETE endNode(r) DELETE r)
MATCH (n:Node)
WHERE NOT (n)--()
RETURN n.name AS orphan
ORDER BY orphan;

Observed results:

  • Neo4j:
A
  • ArcadeDB:
A
B

So the deleted node is not only still visible.
It is also treated as a surviving orphan.

Stronger reproducer from the current feature-only differential
The same family also surfaced in a slightly richer shape:

CREATE (a:Node {name:'A'})-[:REL]->(b:Node {name:'B'})-[:REL]->(c:Node {name:'C'});

MATCH p = ()-[*]->()
WITH p, relationships(p) AS rels
FOREACH (r IN reverse(rels) | DELETE endNode(r) DELETE r)
WITH count(*) AS cnt
OPTIONAL MATCH (n:Node)
WHERE NOT (n)--()
RETURN n.name AS orphan, cnt AS deleted_count
ORDER BY orphan;

Observed results:

  • Neo4j:
A, 3
  • ArcadeDB:
A, 3
B, 3
C, 3

So the wrong visibility can leak through longer pipelines as well.

Why this looks like a real bug
The bad result is not limited to a stale returned value from the deleted node variable itself.
The deleted node can be rediscovered by a fresh later MATCH (n:Node).

That means the later stage is not seeing the same graph state that the earlier delete stage should have produced.

Differential seed
This family surfaced while minimizing:

  • RedisGraph__RedisGraph__1268__q007

Original generated query:

MATCH p = ()-[*]->()
WITH p, relationships(p) AS rels
FOREACH (r IN reverse(rels) | DELETE endNode(r) DELETE r)
WITH count(*) AS cnt
OPTIONAL MATCH (n:Node)
WHERE NOT (n)--()
RETURN n.name AS orphan, cnt AS deleted_count

Direct reduction shows the root issue is already present in the smaller single-edge repro above.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions