When working with Neo4j, you may encounter various database errors that need to be handled gracefully in your application.
The driver exports a Neo4jException class that is inherited by all exceptions thrown by the database.
Common exceptions
AuthenticationException - Raised when authentication fails (incorrect credentials provided)
ClientException - Raised when the client-side error occurs
ConnectionReadTimeoutException - Raised when the connection to the database times out (transaction took longer than timeout - 30 seconds, by default)
DatabaseException - Raised when there is a problem with the database
GqlStatusErrorClassification - Raises an error based on GQL status codes
RetryableException - Indicates retrying the transaction may succeed
ServiceUnavailableException - Raised when the database is unavailable (e.g., server is down or not running)
TransactionTerminatedException - Indicates that a transaction was terminated for some reason
Handling errors
When using the Neo4j Java driver, you can handle errors by catching specific exceptions.
Any errors raised by the DBMS (Neo4jException) will have a message property that describes the error, as well as optional properties for code, gql_status, cause, and more.
java
try (var session = driver.session()) {
// Run a Cypher statement
var result = session.run("MATCH (n) RETURN n LIMIT 10;");
result.forEachRemaining(record -> {
System.out.println(record.get("n").asNode().asMap());
});
} catch (Neo4jException e) {
e.code(); // Outputs the error code
e.getMessage(); // Outputs the error message
e.gqlStatus(); // Outputs the GQL status
e.printStackTrace(); // Outputs full stack trace
}
The gqlStatus property contains an error code that corresponds to an error in the ISO GQL standard. A full list of GQL error codes can be found in Status Codes for Errors & Notifications.
Example: Handling unique constraint violations
One common scenario is dealing with constraint violations when inserting data.
A unique constraint ensures that a property value is unique across all nodes with a specific label.
The following Cypher statement creates a unique constraint named unique_email to ensure that the email property is unique for the User label:
cypher
CREATE CONSTRAINT unique_email IF NOT EXISTS
FOR (u:User) REQUIRE u.email IS UNIQUE;
If a Cypher statement violates this constraint, Neo4j will raise a ConstraintError.
Here’s an example of how to handle a unique constraint violation (pops as a ClientException) when creating a new user:
Java
var name = "Test Name";
var email = "test@test.com";
try (var session = driver.session()) {
var result = session.run("""
CREATE (u:User {name: $name, email: $email})
RETURN u;
""",
Values.parameters("name", name, "email", email));
} catch (ClientException e) {
e.printStackTrace();
// org.neo4j.driver.exceptions.ClientException:
// Node(5) already exists with label `User`
// and property `email` = 'test@test.com'
}
Summary
Proper error handling is crucial for building robust Neo4j applications. By catching and handling specific exceptions:
Your application can gracefully handle expected error conditions
Users receive meaningful feedback
You can implement appropriate recovery strategies
Your application remains stable even when errors occur
Best Practices
Always catch specific exceptions rather than using a generic error
Log errors appropriately for debugging
Provide meaningful feedback to users
Consider implementing retry logic for transient errors