Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 79 additions & 9 deletions java-manual/modules/ROOT/pages/query-simple.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -182,34 +182,100 @@ For those rare use cases, see xref:query-advanced#_dynamic_values_in_property_ke

A query run may fail for a number of reasons, with different link:https://neo4j.com/docs/api/java-driver/{java-driver-version}/org.neo4j.driver/org/neo4j/driver/exceptions/package-summary.html[exceptions] being raised.
When using `Driver.executableQuery()`, the driver automatically retries to run a failed query if the failure is deemed to be transient (for example due to temporary server unavailability).
An error will be raised if the operation keeps failing after the configured link:https://neo4j.com/docs/api/java-driver/{java-driver-version}/org.neo4j.driver/org/neo4j/driver/Config.ConfigBuilder.html#withMaxTransactionRetryTime(long,java.util.concurrent.TimeUnit)[maximum retry time].

All link:https://neo4j.com/docs/status-codes/current/errors/all-errors/[exceptions coming from the server] are subclasses of link:https://neo4j.com/docs/api/java-driver/{java-driver-version}/org.neo4j.driver/org/neo4j/driver/exceptions/Neo4jException.html[`Neo4jException`].
An exception will be raised if the operation keeps failing after the configured link:https://neo4j.com/docs/api/java-driver/{java-driver-version}/org.neo4j.driver/org/neo4j/driver/Config.ConfigBuilder.html#withMaxTransactionRetryTime(long,java.util.concurrent.TimeUnit)[maximum retry time].

All exceptions coming from the server are subclasses of link:https://neo4j.com/docs/api/java-driver/{java-driver-version}/org.neo4j.driver/org/neo4j/driver/exceptions/Neo4jException.html[`Neo4jException`].
You can use an exception's code (retrievable with `.code()`) to stably identify a specific error; error messages are instead not stable markers, and should not be relied upon.

.Basic error handling
[source, java]
[source, java, role=nocollapse]
----
// import import org.neo4j.driver.exceptions.Neo4jException;
// import org.neo4j.driver.exceptions.Neo4jException;

try {
var result = driver.executableQuery("MATCH (p:Person) RETURN ")
.withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
} catch (Neo4jException e) {
System.out.printf("Neo4j error code: %s\n", e.code());
System.out.printf("Exception classification: %s\n", e.rawClassification());
System.out.printf("Exception message: %s\n", e.getMessage());
}
/*
Neo4j error code: Neo.ClientError.Statement.SyntaxError
Exception classification: Optional[CLIENT_ERROR]
Exception message: Invalid input '': expected an expression, '*', 'ALL' or 'DISTINCT' (line 1, column 24 (offset: 23))
"MATCH (p:Person) RETURN"
^
*/
----

Exception objects also expose errors as GQL-status objects.
The main difference between link:https://neo4j.com/docs/status-codes/current/errors/all-errors/[Neo4j error codes] and link:https://neo4j.com/docs/status-codes/current/errors/gql-errors/[GQL error codes] is that the GQL ones are more granular: a single Neo4j error code might be broken in several, more specific GQL error codes.

The actual _cause_ that triggered an exception is sometimes found in the optional GQL-status object retrievable with `.gqlCause()`, which is itself a `Neo4jException`.
You might need to recursively traverse the cause chain before reaching the root cause of the exception you caught.
In the example below, the exception's GQL status code is `42001`, but the actual source of the error has status code `42I06`.

.Usage of `Neo4jException` with GQL-related methods
[source, java]
----
// import org.neo4j.driver.exceptions.Neo4jException;

try {
var result = driver.executableQuery("MATCH (p:Person) RETURN ")
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
} catch (Neo4jException e) {
System.out.printf("Exception GQL status code: %s\n", e.gqlStatus());
System.out.printf("Exception GQL status description: %s\n", e.statusDescription());
System.out.printf("Exception GQL classification: %s\n", e.rawClassification());
System.out.printf("Exception GQL cause: %s\n", e.gqlCause());
System.out.printf("Exception GQL diagnostic record: %s\n", e.diagnosticRecord());
}
/*
Exception GQL status code: 42001
Exception GQL status description: error: syntax error or access rule violation - invalid syntax
Exception GQL classification: Optional[CLIENT_ERROR]
Exception GQL cause: Optional[org.neo4j.driver.exceptions.Neo4jException: 42I06: Invalid input '', expected: an expression, '*', 'ALL' or 'DISTINCT'.]
Exception GQL diagnostic record: {_classification="CLIENT_ERROR", OPERATION_CODE="0", OPERATION="", CURRENT_SCHEMA="/", _position={column: 24, offset: 23, line: 1}}
*/
----

GQL status codes are particularly helpful when you want your application to behave differently depending on the exact error that was raised by the server.

.Distinguishing between different error codes
[source, java]
----
// import org.neo4j.driver.exceptions.Neo4jException;

try {
var result = driver.executableQuery("CREATE (p:Person {name: $name}) RETURN ")
.withParameters(Map.of("name", "Frida"))
.withConfig(QueryConfig.builder().withDatabase("neo4j").build())
.execute();
} catch (Neo4jException e) {
if (e.containsGqlStatus("42001")) {
// Neo.ClientError.Statement.SyntaxError
// special handling of syntax error in query
System.out.println(e.findByGqlStatus("42001").get().getMessage());
} else if (e.containsGqlStatus("42NFF")) {
// Neo.ClientError.Security.Forbidden
// special handling of user not having CREATE permissions
System.out.println(e.findByGqlStatus("42NFF").get().getMessage());
} else {
// handling of all other exceptions
System.out.println(e.getMessage());
}
}
----

[NOTE]
====
The GQL status code `50N42` is returned when an error does not have a GQL-status object.
This can happen if the driver is connected to an older Neo4j server.
Don't rely on this status code, as future Neo4j server versions might change it with a more appropriate one.
====


== Query configuration

Expand Down Expand Up @@ -385,8 +451,12 @@ public class App {
result.summary().resultAvailableAfter(TimeUnit.MILLISECONDS));

} catch (Neo4jException e) {
System.out.println(e.getMessage());
System.exit(1);
if (e.gqlStatus().equals("42NFF")) {
System.out.println("There was a permission issue. Make sure you have correct permissions and try again.");
} else {
System.out.println(e.getMessage());
System.exit(1);
}
}
}
}
Expand Down