We recently migrated to Neo4j version 5.24.1. As part of this migration, we’re removing deprecated functions, including updating the CALL {WITH var}
syntax to the new CALL (var) {}
syntax as recommended in the documentation (Deprecations, additions, and compatibility - Cypher Manual).
During this process, we encountered issues with some of our queries with error empty.tail.
I attempted to replicate the exact issue we’re facing by using mock data.
Steps to reproduce:
Please run the Cypher queries in the database to populate this sample data.
CREATE (n8:Genre {name: "Comedy"})<-[:TYPE_OF]-(potc:Movie {name: "Pirates of the Caribbean", id: 10001})-[:TYPE_OF]->(n7:Genre {name: "Adventure"})<-[:TYPE_OF]-(n3:Movie {name: "Alice in Wonderland", id: 10002})<-[:ACTED_IN]-(johny:Person {name: "Johnny Depp"})-[:ACTED_IN]->(potc)<-[:ACTED_IN]-(:Person {name: "Keira Knightley"})-[:STAYS_IN]->(usa:Country {name: "America"}),
(usa)<-[:STAYS_IN]-(johny)-[:ACTED_IN]->(n4:Movie {name: " Secret Window", id: 10003})-[:TYPE_OF]->(n7),
(:Description {name: "Pirate movie"})<-[:DESCRIBE]-(potc)-[:PART_OF]->(:Movie {name: "The Curse of the Black Pearl", id: 10011}),
(:Description {name: "Fantasy Movie"})<-[:DESCRIBE]-(n3)-[:TYPE_OF]->(n8),
(n4)-[:DESCRIBE]->(:Description {name: "I didnt watch yet"})
The query where we’re encountering the issue is as follows:
=================query 1 starts =======================
MATCH (movie:Movie) where movie.name = 'Pirates of the Caribbean'
MATCH (movie)-[:(ACTED_IN|PART_OF)*1..2]-(actor:Person)-[:ACTED_IN]->(otherMovies:Movie)-[:TYPE_OF]->(:Genre{name:'Adventure'}) WHERE exists((actor)-[:STAYS_IN]->(:Country{name:'America'}))
CALL (movie, otherMovies){
MATCH (otherMovies)-[:DESCRIBE]->(desc:Description)
WHERE NOT desc.name IN ['I didnt watch yet']
RETURN desc AS result
UNION
MATCH (movie)-[:DESCRIBE]->(desc:Description)
WHERE NOT desc.name IN ['I didnt watch yet']
RETURN desc AS result
}
RETURN result
================= query 1 ends ============================
If we replace the new syntax with the deprecated CALL {WITH var}, the query is working fine
================== query2 starts ======================
MATCH (movie:Movie) where movie.name = 'Pirates of the Caribbean'
MATCH (movie)-[:(ACTED_IN|PART_OF)*1..2]-(actor:Person)-[:ACTED_IN]->(otherMovies:Movie)-[:TYPE_OF]->(:Genre{name:'Adventure'}) WHERE exists((actor)-[:STAYS_IN]->(:Country{name:'America'}))
CALL {
WITH movie, otherMovies
MATCH (otherMovies)-[:DESCRIBE]->(desc:Description)
WHERE NOT desc.name IN ['I didnt watch yet']
RETURN desc AS result
UNION
MATCH (movie)-[:DESCRIBE]->(desc:Description)
WHERE NOT desc.name IN ['I didnt watch yet']
RETURN desc AS result
}
RETURN result
================= query2 ends ===================================
I also noticed that if I run with nested CALL (){CALL (){}} syntax the query is working fine
================ query 3 starts ===============================
MATCH (movie:Movie) where movie.name = 'Pirates of the Caribbean'
MATCH (movie)-[:(ACTED_IN|PART_OF)*1..2]-(actor:Person)-[:ACTED_IN]->(otherMovies:Movie)-[:TYPE_OF]->(:Genre{name:'Adventure'}) WHERE exists((actor)-[:STAYS_IN]->(:Country{name:'America'}))
CALL (movie, otherMovies){
CALL (movie, otherMovies){
MATCH (otherMovies)-[:DESCRIBE]->(desc:Description)
WHERE NOT desc.name IN ['I didnt watch yet']
RETURN desc AS result
UNION
MATCH (movie)-[:DESCRIBE]->(desc:Description)
WHERE NOT desc.name IN ['I didnt watch yet']
RETURN desc AS result
}
RETURN result
}
RETURN result
===========query 3 ends ==============================
================== debug.log start ==========================
2024-11-02 08:48:56.247+0000 ERROR [o.n.b.f.StateMachineImpl] Client triggered an unexpected error [Neo.DatabaseError.General.UnknownError]: empty.tail, reference 29f2498e-5630-4364-8bfd-95959e80a080.
2024-11-02 08:48:56.247+0000 ERROR [o.n.b.f.StateMachineImpl] Client triggered an unexpected error [Neo.DatabaseError.General.UnknownError]: empty.tail, reference 29f2498e-5630-4364-8bfd-95959e80a080.
org.neo4j.bolt.protocol.common.fsm.error.TransactionStateTransitionException: empty.tail
at org.neo4j.bolt.protocol.common.fsm.transition.transaction.CreateStatementStateTransition.process(CreateStatementStateTransition.java:56) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.fsm.transition.transaction.CreateStatementStateTransition.process(CreateStatementStateTransition.java:32) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.fsm.transition.transaction.TransactionalStateTransition.process(TransactionalStateTransition.java:42) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.fsm.state.MultiTransitionState.process(MultiTransitionState.java:53) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.fsm.StateMachineImpl.process(StateMachineImpl.java:159) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.connector.connection.AtomicSchedulingConnection$ProcessJob.perform(AtomicSchedulingConnection.java:634) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.connector.connection.AtomicSchedulingConnection.executeJob(AtomicSchedulingConnection.java:338) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.connector.connection.AtomicSchedulingConnection.doExecuteJobs(AtomicSchedulingConnection.java:317) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.connector.connection.AtomicSchedulingConnection.executeJobs(AtomicSchedulingConnection.java:212) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) [?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]
at java.lang.Thread.run(Thread.java:833) [?:?]
Caused by: org.neo4j.bolt.tx.error.statement.StatementExecutionException: empty.tail
at org.neo4j.bolt.tx.TransactionImpl.run(TransactionImpl.java:143) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.fsm.transition.transaction.CreateStatementStateTransition.process(CreateStatementStateTransition.java:48) ~[neo4j-bolt-5.24.1.jar:5.24.1]
... 13 more
Caused by: java.util.NoSuchElementException: empty.tail
at scala.collection.immutable.Vector.last(Vector.scala:292) ~[scala-library-2.13.11.jar:?]
at org.neo4j.cypher.internal.ast.SingleQuery.finalScope(Query.scala:587) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.ast.UnmappedUnion.$anonfun$checkColumnNamesAgree$1(Query.scala:886) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.ast.semantics.SemanticCheckInterpreter$.run(SemanticCheckInterpreter.scala:44) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.ast.semantics.SemanticCheckInterpreter$.runCheck(SemanticCheckInterpreter.scala:28) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.ast.semantics.SemanticCheck.run(SemanticCheck.scala:39) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.ast.semantics.SemanticCheck.run$(SemanticCheck.scala:38) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.ast.semantics.SemanticCheck$FlatMap.run(SemanticCheck.scala:155) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.ast.semantics.SemanticChecker$.check(SemanticChecker.scala:29) ~[neo4j-ast-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.SemanticAnalysis.process(SemanticAnalysis.scala:59) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.SemanticAnalysis.process(SemanticAnalysis.scala:44) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.Phase.$anonfun$transform$1(Phase.scala:36) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.helpers.package$.$anonfun$closing$1(package.scala:25) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.helpers.package$.using(package.scala:34) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.helpers.package$.closing(package.scala:25) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.Phase.transform(Phase.scala:35) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.Phase.transform$(Phase.scala:33) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.SemanticAnalysis.transform(SemanticAnalysis.scala:44) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:103) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.frontend.phases.PipeLine.transform(Transformer.scala:102) ~[neo4j-front-end-5.24.1.jar:5.24.1]
at org.neo4j.cypher.internal.compiler.CypherParsing.parseQuery(CypherParsing.scala:98) ~[neo4j-cypher-planner-5.24.1.jar:5.24.1]
at org.neo4j.router.impl.query.QueryProcessorImpl.parse(QueryProcessorImpl.java:273) ~[neo4j-query-router-5.24.1.jar:5.24.1]
at org.neo4j.router.impl.query.QueryProcessorImpl.prepareQueryForCache(QueryProcessorImpl.java:168) ~[neo4j-query-router-5.24.1.jar:5.24.1]
at org.neo4j.router.impl.query.QueryProcessorImpl.getFromCache(QueryProcessorImpl.java:150) ~[neo4j-query-router-5.24.1.jar:5.24.1]
at org.neo4j.router.impl.query.QueryProcessorImpl.processQuery(QueryProcessorImpl.java:104) ~[neo4j-query-router-5.24.1.jar:5.24.1]
at org.neo4j.router.impl.QueryRouterImpl.executeQuery(QueryRouterImpl.java:229) ~[neo4j-query-router-5.24.1.jar:5.24.1]
at org.neo4j.router.impl.bolt.QueryRouterBoltSpi$Transaction.executeQuery(QueryRouterBoltSpi.java:161) ~[neo4j-query-router-5.24.1.jar:5.24.1]
at org.neo4j.bolt.tx.TransactionImpl.run(TransactionImpl.java:136) ~[neo4j-bolt-5.24.1.jar:5.24.1]
at org.neo4j.bolt.protocol.common.fsm.transition.transaction.CreateStatementStateTransition.process(CreateStatementStateTransition.java:48) ~[neo4j-bolt-5.24.1.jar:5.24.1]
... 13 more
================== debug.log end ==========================
Please let us know why the new CALL (var) { ... UNION ... }
syntax is resulting in an empty.tail
exception.
Could you advise if there is an issue with the way we’re writing these Cypher queries? Alternatively, if this is a Neo4j-related issue, please keep us updated