apache / jena

Apache Jena
https://jena.apache.org/
Apache License 2.0
1.09k stars 646 forks source link

org.apache.jena.fuseki.servlets.ActionErrorException: Cannot read field "succ" because "n" is null #2616

Open agustaf9 opened 1 month ago

agustaf9 commented 1 month ago

Version

5.0.0

What happened?

Steps to Reproduce

  1. Create a new dataset via curl -X POST 'http://localhost:3030/$/datasets' --upload-file ./dsConfigTemplate.ttl --header "Content-Type: text/turtle" where dsConfigTemplate.ttl is:
# https://apothem.blog/apache-jena-fuseki-adding-reasoning-and-full-text-search-capabilities-to-a-dataset.html
PREFIX :       <http://base/#>
PREFIX fuseki: <http://jena.apache.org/fuseki#>
PREFIX ja:     <http://jena.hpl.hp.com/2005/11/Assembler#>
PREFIX rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs:   <http://www.w3.org/2000/01/rdf-schema#>
PREFIX tdb2:   <http://jena.apache.org/2016/tdb#>

:tdb_dataset_readwrite
        rdf:type       tdb2:DatasetTDB2;
        tdb2:location  "/fuseki/databases/ds" . # <-- Change ds to the name of the datastore

:service_tdb_all  rdf:type  fuseki:Service;
        rdfs:label       "TDB2 ds";
        fuseki:dataset :dataset ;
        fuseki:endpoint  [ fuseki:name       "get";
                           fuseki:operation  fuseki:gsp-r
                         ];
        fuseki:endpoint  [ fuseki:operation  fuseki:gsp-rw ];
        fuseki:endpoint  [ fuseki:operation  fuseki:update ];
        fuseki:endpoint  [ fuseki:name       "update";
                           fuseki:operation  fuseki:update
                         ];
        fuseki:endpoint  [ fuseki:name       "sparql";
                           fuseki:operation  fuseki:query
                         ];
        fuseki:endpoint  [ fuseki:operation  fuseki:query ];
        fuseki:endpoint  [ fuseki:name       "data";
                           fuseki:operation  fuseki:gsp-rw
                         ];
        fuseki:endpoint  [ fuseki:name       "query";
                           fuseki:operation  fuseki:query
                         ];
        fuseki:name      "ds" . # <-- Change ds to the name of the datastore
:dataset a ja:RDFDataset ;
    ja:defaultGraph :model_inf .

:model_inf a ja:InfModel ;
     ja:baseModel :graph ;
     ja:reasoner [
         ja:reasonerURL <http://jena.hpl.hp.com/2003/RDFSExptRuleReasoner>
     ] .

:graph rdf:type tdb2:GraphTDB ;
  tdb2:dataset :tdb_dataset_readwrite ;
.
  1. Via the web interface's edit tab, replace all the triples in the default graph with:
    
    PREFIX rdf:         <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    PREFIX rdfs:        <http://www.w3.org/2000/01/rdf-schema#>

rdfs:range rdf:type rdf:Property , rdfs:Resource; rdfs:comment "A range of the subject property."; rdfs:domain rdf:Property; rdfs:isDefinedBy rdfs:; rdfs:label "range"; rdfs:range rdfs:Class; rdfs:seeAlso rdfs:; rdfs:subPropertyOf rdfs:range .

rdfs:subPropertyOf rdf:type rdf:Property , rdfs:Resource; rdfs:comment "The subject is a subproperty of a property."; rdfs:domain rdf:Property; rdfs:isDefinedBy rdfs:; rdfs:label "subPropertyOf"; rdfs:range rdf:Property; rdfs:seeAlso rdfs:; rdfs:subPropertyOf rdfs:subPropertyOf .

3. In the query tab of the web interface, change the `query` endpoint  to `update` and run this query:

DELETE {?s ?p ?o} WHERE { VALUES ?s{ http://www.w3.org/2000/01/rdf-schema#range http://www.w3.org/2000/01/rdf-schema#subPropertyOf } ?s ?p ?o . }

4. Observe Error `Cannot read field "succ" because "n" is null`

### Relevant output and stacktrace

```shell
org.apache.jena.fuseki.servlets.ActionErrorException: Cannot read field "succ" because "n" is null
        at org.apache.jena.fuseki.servlets.ServletOps.errorOccurred(ServletOps.java:275) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.SPARQL_Update.execute(SPARQL_Update.java:259) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.SPARQL_Update.executeBody(SPARQL_Update.java:191) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.SPARQL_Update.execute(SPARQL_Update.java:106) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.ActionService.executeLifecycle(ActionService.java:58) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.SPARQL_Update.execPost(SPARQL_Update.java:91) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.ActionProcessor.process(ActionProcessor.java:34) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.ActionBase.process(ActionBase.java:54) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.ActionExecLib.execActionSub(ActionExecLib.java:127) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.ActionExecLib.execAction(ActionExecLib.java:101) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.server.Dispatcher.dispatchAction(Dispatcher.java:240) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.server.Dispatcher.process(Dispatcher.java:230) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.server.Dispatcher.dispatch(Dispatcher.java:148) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.FusekiFilter.doFilter(FusekiFilter.java:49) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:65) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:109) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:138) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:156) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:70) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:109) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:138) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:156) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:70) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:463) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.AbstractShiroFilter.lambda$doFilterInternal$0(AbstractShiroFilter.java:378) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:91) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:84) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:389) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:376) ~[fuseki-server.jar:5.0.0]
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:156) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.CrossOriginFilter.handle(CrossOriginFilter.java:348) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.CrossOriginFilter.doFilter(CrossOriginFilter.java:301) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:208) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1547) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:814) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:431) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:464) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:571) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:703) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:765) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:597) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.server.Server.handle(Server.java:179) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:619) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:411) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:478) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:441) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:410) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:971) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1201) ~[fuseki-server.jar:5.0.0]
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1156) ~[fuseki-server.jar:5.0.0]
        at java.base/java.lang.Thread.run(Unknown Source) [?:?]
Caused by: java.lang.NullPointerException: Cannot read field "succ" because "n" is null
        at org.apache.jena.reasoner.transitiveReasoner.TransitiveGraphCache.processDeletes(TransitiveGraphCache.java:439) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.reasoner.transitiveReasoner.TransitiveGraphCache.find(TransitiveGraphCache.java:546) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.reasoner.transitiveReasoner.TransitiveEngine.cacheSubPropUtility(TransitiveEngine.java:385) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.reasoner.transitiveReasoner.TransitiveEngine.delete(TransitiveEngine.java:276) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.reasoner.rulesys.FBRuleInfGraph.performDelete(FBRuleInfGraph.java:658) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.graph.impl.GraphBase.delete(GraphBase.java:181) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.core.DatasetGraphCollection.delete(DatasetGraphCollection.java:53) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateEngineWorker.deleteFromDatasetGrap
14:14:38.180 › Fuseki: h(UpdateEngineWorker.java:506) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateEngineWorker.lambda$execDelete$8(UpdateEngineWorker.java:474) ~[fuseki-server.jar:5.0.0]
        at java.base/java.util.ArrayList$Itr.forEachRemaining(Unknown Source) ~[?:?]
        at org.apache.jena.atlas.iterator.IteratorFlatMap.lambda$forEachRemaining$0(IteratorFlatMap.java:94) ~[fuseki-server.jar:5.0.0]
        at java.base/java.util.ArrayList$Itr.forEachRemaining(Unknown Source) ~[?:?]
        at org.apache.jena.atlas.iterator.IteratorFlatMap.forEachRemaining(IteratorFlatMap.java:90) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateEngineWorker.execDelete(UpdateEngineWorker.java:474) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateEngineWorker.execDelete(UpdateEngineWorker.java:463) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateEngineWorker.visit(UpdateEngineWorker.java:384) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.request.UpdateModify.visit(UpdateModify.java:100) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateVisitorSink.send(UpdateVisitorSink.java:45) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateVisitorSink.send(UpdateVisitorSink.java:31) ~[fuseki-server.jar:5.0.0]
        at java.base/java.util.ArrayList$Itr.forEachRemaining(Unknown Source) ~[?:?]
        at java.base/java.util.Collections$UnmodifiableCollection$1.forEachRemaining(Unknown Source) ~[?:?]
        at org.apache.jena.atlas.iterator.Iter.sendToSink(Iter.java:776) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.modify.UpdateProcessorBase.execute(UpdateProcessorBase.java:60) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.sparql.exec.UpdateExecDataset.execute(UpdateExecDataset.java:37) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.update.UpdateAction.execute$(UpdateAction.java:230) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.update.UpdateAction.execute(UpdateAction.java:195) ~[fuseki-server.jar:5.0.0]
        at org.apache.jena.fuseki.servlets.SPARQL_Update.execute(SPARQL_Update.java:231) ~[fuseki-server.jar:5.0.0]
        ... 59 more
[2024-08-01 14:14:38] Fuseki     INFO  [304] 500 Server Error (207 ms)

Are you interested in making a pull request?

No

afs commented 1 month ago

Hi @agustaf9,

Thanks for the complete report.

I've managed to reproduce the problem at my end.

afs commented 3 weeks ago

Reproduced outside Fuseki and reduced to smaller data. The NPE occurs on the attempt to delete rdfs:range rdfs:subPropertyOf rdfs:range.

    public static void testCaseGH2616() {
        JenaSystem.init();
        String PREFIXES = """
                PREFIX rdfs:   <http://www.w3.org/2000/01/rdf-schema#>
                PREFIX rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

                """;
        String queryString = PREFIXES + """
                SELECT * {
                   VALUES ?s { rdfs:range rdfs:subPropertyOf }
                    ?s ?p ?o .
                }
                    """;
        String updateString = PREFIXES + """
                DELETE {?s ?p ?o}
                WHERE {
                   VALUES ?s {
                       ## Only this order, both needed, one single operation.
                       rdfs:range
                       rdfs:subPropertyOf
                    }
                    ?s ?p ?o .
                    ## Exclude this and there is no NPE
                    ##FILTER ( ! ( ?s = rdfs:range && ?p = rdfs:subPropertyOf && ?o = rdfs:range ) )

                    ## No effect - this isn't reached in the gathered triples to delete.
                    ##FILTER ( ! ( ?s = rdfs:subPropertyOf && ?p = rdf:type && ?o = rdf:Property ) )
                }
                    """;

        String data = PREFIXES + """
                    ## Triple that triggers the problem.
                    rdfs:range  rdfs:subPropertyOf  rdfs:range .
                    ## Must be   rdf:type rdf:Property
                    rdfs:subPropertyOf  rdf:type  rdf:Property .
                """;

        Model base = RDFParser.fromString(data, Lang.TTL).toModel();
        InfModel inf = ModelFactory.createRDFSModel(base);

        // This is the delete order
        System.out.println("==== Deletes preview:");
        try ( QueryExecution qExec = QueryExecution.model(inf).query(queryString).build()) {
            ResultSetFormatter.out(qExec.execSelect(),qExec.getQuery());
        }

        System.out.println("==== Update");
        System.out.flush();
        Dataset ds = DatasetFactory.wrap(inf);
        UpdateExecution uExec = UpdateExecution
                    //.model(inf)
                    .dataset(ds)
                    .update(updateString)
                    .build();

        uExec.execute();
        System.out.println("DONE");
    }