Hi there! Newbie here and head-over-heels for Neo4J
BUT, I either have a weird bug on my hands, or some sort of stupid configurational/lack of knowledge kind of screw-up from my side. I hope someone can shed some light on my situation.
My stack:
Kotlin + spring-boot-starter-data-neo4j + neo4j inside a Docker container
The situation:
I have an aggregate root which can be described as:
(Identity)--[MADE]-->(Claim)--[HAS]-->(Fact)
Where Claim is a non-nullable property of Identity and Fact is a non-nullable property of Claim.
All seems to be working just fine about 60% of the time, but sometimes when reconstituting an instance of Identity, the constructor of Claim throws an NPE because it is not presented with an instance of Fact. Even though it is present in the database. The craziest thing is that whenever I encounter this exception, the only option I seem to have is to restart my neo4j container, because it will throw the exception on every try. So it seems it might be related to some random configuration which occurs during startup of Neo4J (or my application of course).
I have no actual clue how the reconstitution of related nodes actually takes place, but I'd imagine it tries to traverse the aggregate root until it has reached all leaves and start with those, then work its way back up. (again, I'm just guessing here, have mercy) But if it is close the how it is done, I don't understand how this exception could ever take place.
Making fact nullable shifted the problem, because fact actually became null and threw havoc at other places in my app.
Just some details below, the record seems to have a perfectly fine "Fact" in it:
org.springframework.data.mapping.MappingException: Error mapping Record<{identity: {Identity_MADE_Claim: [{Claim_HAS_Event: [{actor: "No actor", __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:18", description: "Added new claim", id: "c6a4cfae-f4cc-4da5-ab6f-bdad00fde9c0", version: 1, timestamp: 2023-09-26T08:45:07.005015+02:00, __nodeLabels__: ["IdNode", "Event"], status: "CREATED"}, {actor: "No actor", __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:17", description: "Added aspect to this Claim", id: "a51ebdc6-2e9a-4355-8a91-1e01db74bff0", version: 1, timestamp: 2023-09-26T08:45:07.004989+02:00, __nodeLabels__: ["IdNode", "Event"], status: "MUTATED"}, {actor: "No actor", __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:16", description: "Request was created", id: "e9d91f9d-8aae-4183-b546-fa6e17a794bd", version: 1, timestamp: 2023-09-26T08:45:07.004743+02:00, __nodeLabels__: ["IdNode", "Event"], status: "CREATED"}], Claim_HAS_Aspect: [{id: "d41c0778-2bb1-41ca-bdb4-41d77d327c2d", version: 1, __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:15", __nodeLabels__: ["IdNode", "Aspect"], aspect: "PUBLIC"}], Claim_HAS_Fact: [{Fact_HAS_Event: [{actor: "No actor", __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:13", description: "Added aspect to this Fact", id: "db8cf57b-7331-4411-9213-4277feb53c83", version: 1, timestamp: 2023-09-26T08:45:07.004549+02:00, __nodeLabels__: ["IdNode", "Event"], status: "MUTATED"}, {actor: "No actor", __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:12", description: "Fact was created", id: "fb21f0d0-9127-4e80-a560-cdbf690343fe", version: 1, timestamp: 2023-09-26T08:45:07.004282+02:00, __nodeLabels__: ["IdNode", "Event"], status: "CREATED"}], __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:10", name: "fact-name", description: "fact-description", id: "2cde1971-e405-4279-97d7-2f2a8adcf171", value: "fact-value", version: 1, Fact_HAS_Aspect: [{id: "b51030d4-4223-4387-b49e-ae67cff82019", version: 1, __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:11", __nodeLabels__: ["IdNode", "Aspect"], aspect: "PUBLIC"}], __nodeLabels__: ["IdNode", "Fact", "Topic"]}], __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:14", Claim_HAS_Request: [], id: "ab86ae3b-dc02-45f2-8382-335e7a3511d2", version: 1, __nodeLabels__: ["IdNode", "Topic", "Claim"]}], openForRequests: TRUE, __elementId__: "4:1acc828c-d58e-4ca7-8c19-5ed905752089:3", version: 1, username: "User1", __nodeLabels__: ["Identity"]}}>
With the root cause:
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method core.domain.model.identity.Claim.<init>, parameter fact
at core.domain.model.identity.Claim.<init>(Claim.kt) ~[classes/:na]
at core.domain.model.identity.Claim.<init>(Claim.kt:18) ~[classes/:na]
at core.domain.model.identity.Claim_Instantiator_2virpl.newInstance(Unknown Source) ~[classes/:na]
at org.springframework.data.mapping.model.KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.createInstance(KotlinClassGeneratingEntityInstantiator.java:199) ~[spring-data-commons-3.1.4.jar:3.1.4]
... 168 common frames omitted