Error handling
The Java SDK provides a structured exception hierarchy for handling errors from the database and SDK. All exceptions extend SurrealException, which is an unchecked exception. Server-returned errors are represented as ServerException subclasses with typed error details.
API References
Exception hierarchy
SurrealException is the base class for all exceptions thrown by the SDK. It extends RuntimeException, so exceptions are unchecked. ServerException extends SurrealException and represents errors returned by the SurrealDB server. Specific exception types extend ServerException for common error categories.
Catching server errors
All server errors are ServerException subclasses. Catch specific exceptions first for targeted handling, then fall back to ServerException for unexpected server errors.
try {
db.query("SELECT * FROM protected_table");
} catch (NotAllowedException e) {
System.err.println("Permission denied: " + e.getMessage());
} catch (QueryException e) {
System.err.println("Query failed: " + e.getMessage());
} catch (ServerException e) {
System.err.println("Server error: " + e.getMessage());
}
Inspecting error details
ServerException provides methods for inspecting the error returned by the server.
.getKind() — returns the error kind as a String.getKindEnum() — returns the error kind as an ErrorKind enum value.getDetails() — returns additional error details
The ErrorKind enum includes: VALIDATION, CONFIGURATION, THROWN, QUERY, SERIALIZATION, NOT_ALLOWED, NOT_FOUND, ALREADY_EXISTS, CONNECTION, INTERNAL, and UNKNOWN.
try {
db.query("INVALID QUERY");
} catch (ServerException e) {
ErrorKind kind = e.getKindEnum();
String details = e.getDetails();
System.err.println(kind + ": " + details);
}
Traversing error chains
Server errors can have nested causes. ServerException provides methods for walking the cause chain to find a specific error type.
.getServerCause() — returns the underlying ServerException cause, if any.hasKind(kind) — checks whether this error or any cause matches the given ErrorKind.findCause(kind) — searches the cause chain and returns the first ServerException matching the given ErrorKind
try {
db.query("SELECT * FROM users");
} catch (ServerException e) {
if (e.hasKind(ErrorKind.NOT_ALLOWED)) {
ServerException cause = e.findCause(ErrorKind.NOT_ALLOWED);
System.err.println("Permission error: " + cause.getDetails());
}
}
Handling specific error types
Specific exception subclasses expose additional context about the error.
NotFoundException provides .getTableName() and .getRecordId() to identify the missing resource.
try {
Optional<Value> user = db.select(new RecordId("users", "nonexistent"));
} catch (NotFoundException e) {
System.err.println("Table: " + e.getTableName());
System.err.println("Record: " + e.getRecordId());
}
NotAllowedException provides .isTokenExpired() and .isInvalidAuth() to distinguish authentication failures.
try {
db.query("SELECT * FROM protected");
} catch (NotAllowedException e) {
if (e.isTokenExpired()) {
System.err.println("Token expired, re-authenticate");
} else if (e.isInvalidAuth()) {
System.err.println("Invalid credentials");
}
}
QueryException provides .isTimedOut() and .isCancelled() to identify query lifecycle issues.
try {
db.query("SELECT * FROM large_table");
} catch (QueryException e) {
if (e.isTimedOut()) {
System.err.println("Query timed out");
} else if (e.isCancelled()) {
System.err.println("Query was cancelled");
}
}
Learn more