# Error handling

The Go SDK provides structured error types for distinguishing between server errors, query errors, and transport failures.

The Go SDK uses Go's standard `error` interface and the `errors.As` / `errors.Is` functions for error handling. Errors fall into three main categories: structured [server errors](/docs/reference/golang/api/errors.md#servererror) from SurrealDB, per-statement [query errors](/docs/reference/golang/api/errors.md#queryerror), and transport-level failures.

The error kinds, wire codes and structured shape behind these are documented once in [Errors](/docs/reference/rest-api/errors.md), which applies to every SDK and protocol.

This page covers how to identify and handle each error type, and which errors are safe to retry.

## API references

<table>
	<thead>
		<tr>
			<th scope="col">Error type</th>
			<th scope="col">Description</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td scope="row" data-label="Error type"><a href="/docs/reference/golang/api/errors.md#servererror"><code>ServerError</code></a></td>
			<td scope="row" data-label="Description">Structured error from SurrealDB v3 with kind, details, and cause chain</td>
		</tr>
		<tr>
			<td scope="row" data-label="Error type"><a href="/docs/reference/golang/api/errors.md#queryerror"><code>QueryError</code></a></td>
			<td scope="row" data-label="Description">Per-statement query failure returned within QueryResult</td>
		</tr>
		<tr>
			<td scope="row" data-label="Error type"><a href="/docs/reference/golang/api/errors.md#rpcerror"><code>RPCError</code></a></td>
			<td scope="row" data-label="Description">RPC error (deprecated in favour of ServerError on v3)</td>
		</tr>
	</tbody>
</table>

## Handling structured server errors

SurrealDB v3 returns structured errors with a `Kind`, `Message`, `Details`, and an optional `Cause` chain. Use `errors.As` to extract a [`ServerError`](/docs/reference/golang/api/errors.md#servererror):

```go
import "errors"

_, err := surrealdb.Select[Person](ctx, db, models.NewRecordID("persons", "missing"))
if err != nil {
	var se *surrealdb.ServerError
	if errors.As(err, &se) {
		fmt.Println("Kind:", se.Kind)
		fmt.Println("Message:", se.Message)
		if se.Cause != nil {
			fmt.Println("Caused by:", se.Cause.Message)
		}
	}
}
```

The `Cause` field forms a linked list. Use `errors.Unwrap` or iterate through `Cause` to traverse the full chain.

## Handling query errors

When using `Query`, individual statements can fail without causing the entire call to error. Each [`QueryResult`](/docs/reference/golang/api/types.md#queryresult) has an `Error` field that contains a [`QueryError`](/docs/reference/golang/api/errors.md#queryerror) if that statement failed.

```go
results, err := surrealdb.Query[[]any](ctx, db,
	"SELECT * FROM persons; INVALID STATEMENT;",
	nil,
)

for i, qr := range *results {
	if qr.Error != nil {
		fmt.Printf("Statement %d failed: %s\n", i, qr.Error.Message)
	}
}
```

The `err` returned by `Query` is a joined error containing all per-statement `QueryError` values. You can check it directly:

```go
if errors.Is(err, &surrealdb.QueryError{}) {
	fmt.Println("One or more statements failed")
}
```

## Handling sentinel errors

The SDK defines several [sentinel errors](/docs/reference/golang/api/errors.md#sentinel-errors) for common failure conditions:

| Error | Description |
|---|---|
| `constants.ErrSessionsNotSupported` | Sessions require a WebSocket connection |
| `constants.ErrTransactionsNotSupported` | Interactive transactions require a WebSocket connection |
| `constants.ErrSessionClosed` | The session has been detached |
| `constants.ErrTransactionClosed` | The transaction has been committed or cancelled |

Check for these using `errors.Is`:

```go
import "github.com/surrealdb/surrealdb.go/pkg/constants"

if errors.Is(err, constants.ErrSessionClosed) {
	fmt.Println("Session was already detached")
}
```

## Deciding whether to retry

Not all errors are safe to retry. Use the following guidelines:

| Error type | Retriable | Reason |
|---|---|---|
| `ServerError` | Sometimes | Depends on the error kind; network-related kinds may be retriable |
| `QueryError` | No | The query itself is invalid or caused a logical error |
| `RPCError` (from `Query`) | Yes | The RPC failed before the query was processed |
| `RPCError` (from other methods) | No | May indicate a data-level error (e.g., duplicate record) |
| Unmarshal errors | No | Type mismatch between expected and actual response |

## Learn more

- [Errors API reference](/docs/reference/golang/api/errors.md) for complete error type definitions
- [Executing queries](/docs/reference/golang/concepts/executing-queries.md) for query-level error handling
- [Types reference](/docs/reference/golang/api/types.md) for `QueryResult` and `QueryError` definitions
