Batch REST calls return cryptic error messages. #906

Open
jonpacker opened this Issue Jun 25, 2013 · 4 comments

Comments

Projects
None yet
6 participants

Here's a couple of examples. When creating a unique node, in the event of a conflict, with the normal API a 409 is returned, as such:

POST   http://127.0.0.1:25911/db/data/index/node/singers?uniqueness=create_or_fail
--- BODY ---
{
 "key": "name",
 "value": "johanna",
 "properties": {
  "name": "Johanna"
 }
}
------------

RESPONSE
Content-Type: application/json
Status code: 409
--- BODY ---
{ extensions: {},
  outgoing_relationships: 'http://127.0.0.1:25911/db/data/node/4/relationships/out',
  labels: 'http://127.0.0.1:25911/db/data/node/4/labels',
  all_typed_relationships: 'http://127.0.0.1:25911/db/data/node/4/relationships/all/{-list|&|types}',
  traverse: 'http://127.0.0.1:25911/db/data/node/4/traverse/{returnType}',
  self: 'http://127.0.0.1:25911/db/data/node/4',
  property: 'http://127.0.0.1:25911/db/data/node/4/properties/{key}',
  outgoing_typed_relationships: 'http://127.0.0.1:25911/db/data/node/4/relationships/out/{-list|&|types}',
  properties: 'http://127.0.0.1:25911/db/data/node/4/properties',
  incoming_relationships: 'http://127.0.0.1:25911/db/data/node/4/relationships/in',
  create_relationship: 'http://127.0.0.1:25911/db/data/node/4/relationships',
  paged_traverse: 'http://127.0.0.1:25911/db/data/node/4/paged/traverse/{returnType}{?pageSize,leaseTime}',
  all_relationships: 'http://127.0.0.1:25911/db/data/node/4/relationships/all',
  incoming_typed_relationships: 'http://127.0.0.1:25911/db/data/node/4/relationships/in/{-list|&|types}',
  data: { name: 'Johanna' },
  indexed: 'http://127.0.0.1:25911/db/data/index/node/singers/name/johanna/4' }
------------

The 409 makes it clear that the request failed because of a conflict. If I do it in a batch, this is what I get back:

POST   http://127.0.0.1:25911/db/data/batch
--- BODY ---
[
 {
  "method": "POST",
  "to": "index/node/singers?uniqueness=create_or_fail",
  "body": {
   "key": "name",
   "value": "johanna",
   "properties": {
    "name": "Johanna"
   }
  },
  "id": 0
 }
]
------------

RESPONSE
Content-Type: application/json
Status code: 500
--- BODY ---
{ message: '{\n  "extensions" : {\n  },\n  "outgoing_relationships" : "http://127.0.0.1:25911/db/data/node/4/relationships/out",\n  "labels" : "http://127.0.0.1:25911/db/data/node/4/labels",\n  "all_typed_relationships" : "http://127.0.0.1:25911/db/data/node/4/relationships/all/{-list|&|types}",\n  "traverse" : "http://127.0.0.1:25911/db/data/node/4/traverse/{returnType}",\n  "self" : "http://127.0.0.1:25911/db/data/node/4",\n  "property" : "http://127.0.0.1:25911/db/data/node/4/properties/{key}",\n  "outgoing_typed_relationships" : "http://127.0.0.1:25911/db/data/node/4/relationships/out/{-list|&|types}",\n  "properties" : "http://127.0.0.1:25911/db/data/node/4/properties",\n  "incoming_relationships" : "http://127.0.0.1:25911/db/data/node/4/relationships/in",\n  "create_relationship" : "http://127.0.0.1:25911/db/data/node/4/relationships",\n  "paged_traverse" : "http://127.0.0.1:25911/db/data/node/4/paged/traverse/{returnType}{?pageSize,leaseTime}",\n  "all_relationships" : "http://127.0.0.1:25911/db/data/node/4/relationships/all",\n  "incoming_typed_relationships" : "http://127.0.0.1:25911/db/data/node/4/relationships/in/{-list|&|types}",\n  "data" : {\n    "name" : "Johanna"\n  },\n  "indexed" : "http://127.0.0.1:25911/db/data/index/node/singers/name/johanna/4"\n}',
  exception: 'BatchOperationFailedException',
  fullname: 'org.neo4j.server.rest.domain.BatchOperationFailedException',
  stacktrace:
   [ 'org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:63)',
     'org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:188)',
     'org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:159)',
     'org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)',
     'org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:117)',
     'org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:71)',
     'java.lang.reflect.Method.invoke(Method.java:597)',
     'org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)' ] }
------------

I understand that it's returning a BatchOperationException but it would be nice if it returned the underlying error that caused the exception in the first place. Right now there's no easy way to find out that this was caused by a uniqueness conflict.

Here's another example, in trying to read a non-existent node. Regularly you would expect a 404, such as this:

GET   http://127.0.0.1:25911/db/data/node/25125/properties

RESPONSE
Content-Type: application/json
Status code: 404
--- BODY ---
{
  "message" : "Cannot find node with id [25125] in database.",
  "exception" : "NodeNotFoundException",
  "fullname" : "org.neo4j.server.rest.web.NodeNotFoundException",
  "stacktrace" : [ "org.neo4j.server.rest.web.DatabaseActions.node(DatabaseActions.java:179)", "org.neo4j.server.rest.web.DatabaseActions.getAllNodeProperties(DatabaseActions.java:323)", "org.neo4j.server.rest.web.RestfulGraphDatabase.getAllNodeProperties(RestfulGraphDatabase.java:322)", "java.lang.reflect.Method.invoke(Method.java:597)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]
}
------------

But if you do this in a batch, you get this:

RESPONSE
Content-Type: application/json
Status code: 500
--- BODY ---
{ message: '{\n  "message" : "Cannot find node with id [25125] in database.",\n  "exception" : "NodeNotFoundException",\n  "fullname" : "org.neo4j.server.rest.web.NodeNotFoundException",\n  "stacktrace" : [ "org.neo4j.server.rest.web.DatabaseActions.node(DatabaseActions.java:179)", "org.neo4j.server.rest.web.DatabaseActions.getAllNodeProperties(DatabaseActions.java:323)", "org.neo4j.server.rest.web.RestfulGraphDatabase.getAllNodeProperties(RestfulGraphDatabase.java:322)", "java.lang.reflect.Method.invoke(Method.java:597)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "org.neo4j.server.web.Jetty6WebServer.invokeDirectly(Jetty6WebServer.java:291)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:55)", "org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:188)", "org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:159)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)", "org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:117)", "org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:71)", "java.lang.reflect.Method.invoke(Method.java:597)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]\n}',
  exception: 'BatchOperationFailedException',
  fullname: 'org.neo4j.server.rest.domain.BatchOperationFailedException',
  stacktrace:
   [ 'org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:63)',
     'org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:188)',
     'org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:159)',
     'org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)',
     'org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:117)',
     'org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:71)',
     'java.lang.reflect.Method.invoke(Method.java:597)',
     'org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)' ] }
------------

It's much easier to tell what's going on this time, but I still have no way of finding a 404 from that, which is what the actual exception was.

I'd be ok with the original exception being nested inside the BatchOperationFailedException, so long as I have access to it and can find the original status code.

This is a big hitch for me when using batching, so I'd be grateful for any help you guys can give.

Contributor

technige commented Jun 25, 2013

This issue has broken some tests for me in py2neo as well. Instead of returning the traditional 409 (which is checked for) the error is now a 500 (which isn't). Since the docs haven't been updated, can I assume this is unintentional and therefore a bug?

Owner

simpsonjulian commented Jun 25, 2013

Hey @jonpacker, what version of Neo4j could someone reproduce this on?

@simpsonjulian you can reproduce on 2.0.0-M03 (but it was also happening on 1.9.M05, and before)

Member

jexp commented Sep 21, 2013

Actually it would even make sense to use the http status code that was produced by the original call, only in streaming mode the header and previous data has already been sent, so no way to use a different header altogether.

I see your argument about not wrapping it in a batch-exception or at least exposing the original exception and error code sensibly.

I try to find time to look into it.

davidegrohmann removed the server label Oct 22, 2015

jakewins added the remoting label Dec 6, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment