# Errors

The Java SDK provides a structured exception hierarchy for handling errors from SurrealDB.

The Java SDK uses a hierarchy of exceptions rooted at `SurrealException`. Server-returned errors are represented by `ServerException` and its subclasses, which provide structured access to error details, kinds, and cause chains.

**Source:** [surrealdb.java](https://github.com/surrealdb/surrealdb.java)

---

## Exception hierarchy

- `SurrealException` (extends `RuntimeException`)
  - `ServerException`
    - `NotFoundException`
    - `NotAllowedException`
    - `QueryException`
    - `AlreadyExistsException`
    - `ValidationException`
    - `ConfigurationException`
    - `SerializationException`
    - `InternalException`
    - `ThrownException`

---

## `SurrealException` {#surreal-exception}

Base exception for all SDK errors. Extends `RuntimeException`.

All exceptions thrown by the Java SDK are subclasses of `SurrealException`, making it possible to catch all SDK-related errors with a single catch block.

```java title="Example"
try {
    db.query("SELECT * FROM users");
} catch (SurrealException e) {
    System.err.println("SDK error: " + e.getMessage());
}
```

---

## `ServerException` {#server-exception}

Base class for all server-returned errors. Extends `SurrealException`.

`ServerException` provides structured access to the error kind, details, and cause chain returned by the server. All specific server error types extend this class.

### `.getKind()` {#get-kind}

Returns the error kind as a string.

```java title="Method Syntax"
exception.getKind()
```

**Returns:** `String`

```java title="Example"
try {
    db.select(Person.class, new RecordId("person", "missing"));
} catch (ServerException e) {
    String kind = e.getKind();
}
```

### `.getKindEnum()` {#get-kind-enum}

Returns the error kind as an [`ErrorKind`](#error-kind) enum value.

```java title="Method Syntax"
exception.getKindEnum()
```

**Returns:** `ErrorKind`

```java title="Example"
try {
    db.query("INVALID QUERY");
} catch (ServerException e) {
    ErrorKind kind = e.getKindEnum();
}
```

### `.getDetails()` {#get-details}

Returns structured error details provided by the server.

```java title="Method Syntax"
exception.getDetails()
```

**Returns:** `Object`

### `.getServerCause()` {#get-server-cause}

Returns the typed server cause if the error was caused by another server error.

```java title="Method Syntax"
exception.getServerCause()
```

**Returns:** `ServerException`

### `.hasKind(kind)` {#has-kind}

Checks if the error or any error in its cause chain matches a specific kind.

```java title="Method Syntax"
exception.hasKind(kind)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>kind</code> _(required)_</td>
            <td><code>String</code> or <code>ErrorKind</code></td>
            <td>The error kind to check for.</td>
        </tr>
    </tbody>
</table>

**Returns:** `boolean`

```java title="Example"
try {
    db.query("SELECT * FROM protected_table");
} catch (ServerException e) {
    if (e.hasKind(ErrorKind.NOT_ALLOWED)) {
        System.err.println("Permission denied");
    }
}
```

### `.findCause(kind)` {#find-cause}

Finds the first error in the cause chain that matches a specific kind.

```java title="Method Syntax"
exception.findCause(kind)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>kind</code> _(required)_</td>
            <td><code>String</code> or <code>ErrorKind</code></td>
            <td>The error kind to search for.</td>
        </tr>
    </tbody>
</table>

**Returns:** `ServerException`

```java title="Example"
try {
    db.query("CREATE person SET name = 'Alice'");
} catch (ServerException e) {
    ServerException cause = e.findCause(ErrorKind.ALREADY_EXISTS);
    if (cause != null) {
        System.err.println("Duplicate: " + cause.getMessage());
    }
}
```

---

## `ErrorKind` {#error-kind}

Enum representing error categories returned by the server.

| Value | Description |
|---|---|
| `VALIDATION` | Data validation failed |
| `CONFIGURATION` | Configuration error |
| `THROWN` | Explicitly thrown error from SurrealQL |
| `QUERY` | Query execution error |
| `SERIALIZATION` | Serialisation/deserialisation error |
| `NOT_ALLOWED` | Operation not permitted |
| `NOT_FOUND` | Resource not found |
| `ALREADY_EXISTS` | Resource already exists |
| `CONNECTION` | Connection error |
| `INTERNAL` | Internal server error |
| `UNKNOWN` | Unknown error kind |

### `ErrorKind.fromString(kind)` {#from-string}

Converts a string to an `ErrorKind` enum value. Returns `UNKNOWN` if the string does not match any known kind.

```java title="Method Syntax"
ErrorKind.fromString(kind)
```

<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>kind</code> _(required)_</td>
            <td><code>String</code></td>
            <td>The error kind string to convert.</td>
        </tr>
    </tbody>
</table>

**Returns:** `ErrorKind`

```java title="Example"
ErrorKind kind = ErrorKind.fromString("NotFound");
```

---

## `NotFoundException` {#not-found-exception}

Thrown when a requested resource does not exist. Extends `ServerException`.

### Additional methods

| Method | Returns | Description |
|---|---|---|
| `.getTableName()` | `String` | The table that was queried |
| `.getRecordId()` | `String` | The record ID that was not found |
| `.getMethodName()` | `String` | The method that triggered the error |
| `.getNamespaceName()` | `String` | The namespace that was not found |
| `.getDatabaseName()` | `String` | The database that was not found |
| `.getSessionId()` | `String` | The session ID that was not found |

```java title="Example"
try {
    db.select(Person.class, new RecordId("person", "nonexistent"));
} catch (NotFoundException e) {
    String table = e.getTableName();
    String record = e.getRecordId();
}
```

---

## `NotAllowedException` {#not-allowed-exception}

Thrown when an operation is not permitted. Extends `ServerException`.

### Additional methods

| Method | Returns | Description |
|---|---|---|
| `.isTokenExpired()` | `boolean` | Whether the authentication token has expired |
| `.isInvalidAuth()` | `boolean` | Whether the authentication credentials are invalid |
| `.isScriptingBlocked()` | `boolean` | Whether scripting is disabled on the server |
| `.getMethodName()` | `String` | The method that was not allowed |
| `.getFunctionName()` | `String` | The function that was not allowed |
| `.getTargetName()` | `String` | The target resource that was not accessible |

```java title="Example"
try {
    db.query("SELECT * FROM protected_table");
} catch (NotAllowedException e) {
    if (e.isTokenExpired()) {
        db.signin(new RootCredential("root", "root"));
    }
}
```

---

## `QueryException` {#query-exception}

Thrown when a query fails to execute. Extends `ServerException`.

### Additional methods

| Method | Returns | Description |
|---|---|---|
| `.isNotExecuted()` | `boolean` | Whether the query was not executed |
| `.isTimedOut()` | `boolean` | Whether the query timed out |
| `.isCancelled()` | `boolean` | Whether the query was cancelled |
| `.getTimeout()` | `Map<String, Object>` | The timeout details if the query timed out |

```java title="Example"
try {
    db.query("SELECT * FROM large_table TIMEOUT 1s");
} catch (QueryException e) {
    if (e.isTimedOut()) {
        System.err.println("Query timed out: " + e.getTimeout());
    }
}
```

---

## `AlreadyExistsException` {#already-exists-exception}

Thrown when attempting to create a resource that already exists. Extends `ServerException`.

### Additional methods

| Method | Returns | Description |
|---|---|---|
| `.getRecordId()` | `String` | The record ID that already exists |
| `.getTableName()` | `String` | The table containing the duplicate |
| `.getSessionId()` | `String` | The session ID that already exists |
| `.getNamespaceName()` | `String` | The namespace that already exists |
| `.getDatabaseName()` | `String` | The database that already exists |

```java title="Example"
try {
    db.create(Person.class, new RecordId("person", "alice"), person);
} catch (AlreadyExistsException e) {
    String recordId = e.getRecordId();
}
```

---

## `ValidationException` {#validation-exception}

Thrown when data validation fails. Extends `ServerException`. No additional methods.

---

## `ConfigurationException` {#configuration-exception}

Thrown when there is a configuration error. Extends `ServerException`. No additional methods.

---

## `SerializationException` {#serialization-exception}

Thrown when serialisation or deserialisation fails. Extends `ServerException`. No additional methods.

---

## `InternalException` {#internal-exception}

Thrown for internal server errors. Extends `ServerException`. No additional methods.

---

## `ThrownException` {#thrown-exception}

Thrown when a SurrealQL [`THROW`](/docs/reference/query-language/statements/throw.md) statement is executed. Extends `ServerException`. No additional methods.

```java title="Example"
try {
    db.query("THROW 'custom error message'");
} catch (ThrownException e) {
    System.err.println("SurrealQL threw: " + e.getMessage());
}
```

---

## See also

- [Surreal](/docs/reference/java/api/core/surreal.md) - Connection and method reference
- [Error handling](/docs/reference/java/concepts/error-handling.md) - Error handling concepts and patterns
- [SurrealQL THROW](/docs/reference/query-language/statements/throw.md) - Throwing custom errors from queries
