Skip to content

API Reference

/

Errors

Errors

Every exception that the Python SDK raises for a failed operation is a subclass of SurrealError. This page lists each class with what raises it and the properties it carries. A mistake in the arguments of a call raises Python's own TypeError or ValueError instead. Error handling shows how to catch these errors and which ones to retry.

Every class on this page is exported from surrealdb:

from surrealdb import NotFoundError, ServerError, SurrealError, TransportError

The classes form this hierarchy:

Hierarchy
SurrealError
├── ServerError
│   ├── ValidationError
│   ├── ConfigurationError
│   ├── ThrownError
│   ├── QueryError
│   ├── SerializationError
│   ├── NotAllowedError
│   ├── NotFoundError
│   ├── AlreadyExistsError
│   └── InternalError
├── TransportError
│   ├── ConnectionUnavailableError
│   ├── TransportTimeoutError
│   └── HttpStatusError
├── UnsupportedFeatureError
│   └── UnavailableFeatureError
├── UnsupportedVersionError
├── UnsupportedEngineError
├── InvalidUrlError
├── ImportFailedError
├── UnexpectedResponseError
├── InvalidRecordIdError
├── InvalidDurationError
├── InvalidGeometryError
└── InvalidTableError

Source: errors.py

Extends: Exception

Base class for every error that the SDK raises. Catch it to handle any failure of an SDK call in one place.

from surrealdb import SurrealError, Table

try:
    people = db.select(Table("person")).execute()
except SurrealError as error:
    print(f"{type(error).__name__}: {error}")

A server error is a failure that the server reported in its structured error format. The SDK chooses the class from the kind of the error, as listed under ErrorKind. SurrealDB 2.x sends no kind, so on a 2.x server every server error is an InternalError. Errors describes the kinds, details and wire codes that the server sends.

Extends: SurrealError

A failure that the server reported, with its kind, details and cause chain. Every class in this section extends it. A kind without a class of its own, such as Connection or a kind added by a newer server, arrives as a ServerError with its kind set. str(error) is the message of the server, and repr() shows the class and kind, such as ThrownError(kind='Thrown', message='An error occurred: nope').

Syntax
ServerError(kind, message, code=0, details=None, cause=None)

The SDK builds server errors from the answers of the server. Construct one yourself only to test your own error handling.

Property

Type

Description

kindstr

The kind of the error, such as

"NotAllowed"

or

"NotFound"

. Compare it with the

ErrorKind

constants.

codeint

The JSON-RPC wire code, kept for compatibility.

0

when the server sends none, as for an error in a statement.

detailsdict[str, Any] | None

The reason for the error, as a dict with a

"kind"

key and, for a reason that carries values, a

"details"

key.

None

when the server sends no reason. The properties of each subclass read it for you.

server_causeServerError | None

The server error that caused this one, if the server sent one. It is also the

__cause__

of the exception.

Checks whether this error, or any error in its chain of causes, has the given kind.

Syntax
error.has_kind(kind)

Parameter

Type

Description

kindstr

An error kind, such as

ErrorKind.NOT_FOUND

.

Returns: bool

Returns the first error with the given kind: this error, or the first error in its chain of causes.

Syntax
error.find_cause(kind)

Parameter

Type

Description

kindstr

An error kind, such as

ErrorKind.NOT_FOUND

.

Returns: ServerError | None

from surrealdb import ErrorKind, ServerError, Table

try:
    db.select(Table("post_archive")).execute()
except ServerError as error:
    print(error.has_kind(ErrorKind.NOT_FOUND))
    print(error.find_cause(ErrorKind.NOT_FOUND).details)
Output
True
{'details': {'name': 'post_archive'}, 'kind': 'Table'}

Extends: ServerError

A request or a query that is not valid: a parse error, invalid parameters, or a value that does not fit the schema.

PropertyTypeDescription
is_parse_errorboolWhether the reason in details is Parse. SurrealDB 3.x and 4.0 send a parse error in a query without details, so it is False for that error.
parameter_namestr | NoneThe name of the invalid parameter, for the reason InvalidParameter

Extends: ServerError

A feature or a configuration that the server does not support, such as live queries or GraphQL.

PropertyTypeDescription
is_live_query_not_supportedboolWhether the server does not support live queries

Extends: ServerError

An error raised by a THROW statement in SurrealQL, including one in a function.

from surrealdb import ThrownError

try:
    db.query("THROW 'Order not found'").execute()
except ThrownError as error:
    print(error)
Output
An error occurred: Order not found

Extends: ServerError

A query that did not finish: it timed out, was cancelled, was not run because an earlier statement in its transaction failed, or conflicted with another transaction.

PropertyTypeDescription
is_not_executedboolWhether the statement was not run, such as one in a transaction after a statement that failed
is_timed_outboolWhether the statement ran past its TIMEOUT
is_cancelledboolWhether the statement was cancelled
is_transaction_conflictboolWhether the transaction conflicted with another one. The server marks this reason as one that can be retried.
timeoutDuration | NoneThe timeout that the statement ran past, or None for a reason other than TimedOut
from surrealdb import QueryError

try:
    db.query("SELECT * FROM sleep(500ms) TIMEOUT 50ms").execute()
except QueryError as error:
    print(error.is_timed_out, error.timeout)
Output
True 50ms

A QueryError timeout is enforced by the server. When the SDK stops waiting for a reply, it raises TransportTimeoutError instead.

Extends: ServerError

A value that the server could not serialise or deserialise.

PropertyTypeDescription
is_deserializationboolWhether the failure was in deserialisation

Extends: ServerError

A refused authentication, or a method, function or target that the session may not use.

PropertyTypeDescription
is_token_expiredboolWhether the authentication token has expired
is_invalid_authboolWhether the credentials or the token are invalid
is_scripting_blockedboolWhether embedded scripting is not allowed
method_namestr | NoneThe name of the method that is not allowed
function_namestr | NoneThe name of the function that is not allowed
target_namestr | NoneThe name of the target that is not allowed
from surrealdb import NotAllowedError, Surreal

with Surreal("ws://localhost:8000") as db:
    try:
        db.signin({"username": "root", "password": "wrong"})
    except NotAllowedError as error:
        print(error.is_invalid_auth, error.is_token_expired)
Output
True False

A record user whose SIGNIN clause matches no record gets NotFoundError with the message No record was returned. A table permission that denies a statement does not raise at all: the statement returns an empty result.

Extends: ServerError

A resource that does not exist, such as a table, a namespace, a database, a method or a session. From SurrealDB 3.0, a statement or a live query on a table that does not exist raises it, also for one record of that table. select() of a record that does not exist, in a table that does, returns None and does not raise.

PropertyTypeDescription
table_namestr | NoneThe name of the table that does not exist
record_idstr | NoneThe id of the record that does not exist
method_namestr | NoneThe name of the method that does not exist
namespace_namestr | NoneThe name of the namespace that does not exist
database_namestr | NoneThe name of the database that does not exist
session_idstr | NoneThe id of the session that does not exist
from surrealdb import NotFoundError, Table

try:
    db.select(Table("post_archive")).execute()
except NotFoundError as error:
    print(error.table_name, "|", error)
Output
post_archive | The table 'post_archive' does not exist

Extends: ServerError

A resource that already exists, such as a record, a table or a namespace.

PropertyTypeDescription
record_idstr | NoneThe id of the record that already exists, such as "person:tobie"
table_namestr | NoneThe name of the table that already exists
session_idstr | NoneThe id of the session that already exists
namespace_namestr | NoneThe name of the namespace that already exists
database_namestr | NoneThe name of the database that already exists

Extends: ServerError

An internal or unexpected failure on the server, and the class for every server error from SurrealDB 2.x, which sends no kind. SurrealDB 3.x and 4.0 also report some mistakes in a query with this kind, such as a function called with the wrong number of arguments, a function that does not exist, and a bucket that does not exist.

Another name for ServerError, kept so that code written for earlier versions of the SDK still runs. except SurrealDBMethodError catches every server error. Use ServerError in new code.

A transport error means that a request got no answer from the server in the structured error format: it could not be sent, no reply arrived in time, or the reply was an HTTP error status. The same request can succeed when you send it again, but the error does not tell you whether the server ran it. Each transport error keeps the exception of the underlying library, such as a ConnectionRefusedError or a requests exception, as __cause__.

Extends: SurrealError

Base class for the three transport errors below. Catch it to retry a request whatever the transport failure was.

Extends: TransportError

Raised when the server cannot be reached, when the socket closes while a request waits for its reply, and when a live subscription is read after the connection that served it was lost. A request that was in flight when the socket dropped is not sent again, because it may already have run. An asynchronous connection used from a second event loop also raises it.

from surrealdb import ConnectionUnavailableError, Surreal

db = Surreal("ws://localhost:8001")

try:
    db.connect()
except ConnectionUnavailableError as error:
    print(type(error.__cause__).__name__)
Output
ConnectionRefusedError

Extends: TransportError

No reply arrived within the timeout of the connection, 30 seconds by default, or within a db.timeout() block. The server can still be running the request.

from surrealdb import TransportTimeoutError

try:
    with db.timeout(0.5):
        db.query("SLEEP 2s").execute()
except TransportTimeoutError as error:
    print(error)
Sample output
timed out while query: no answer within 0.5s

Extends: TransportError

An HTTP connection got a response with a status outside the 2xx range. SurrealDB answers some failures at the HTTP layer, with a plain body and no structured error, so a token that the server refuses over HTTP raises HttpStatusError with status 401, where a WebSocket connection raises NotAllowedError.

Syntax
HttpStatusError(status, body, url)
PropertyTypeDescription
statusintThe HTTP status code
bodystrThe body of the response as text, shortened if it is long. Empty when the response has no body.
urlstrThe URL that the request was sent to
from surrealdb import HttpStatusError, Surreal

with Surreal("http://localhost:8000") as db:
    try:
        db.authenticate(token)
    except HttpStatusError as error:
        print(error)
Output
HTTP 401 from http://localhost:8000/rpc: There was a problem with authentication

Here token holds an access token that the server refuses.

These errors come from the SDK itself, without a request to the server, or from what the SDK found in an answer.

Extends: SurrealError

The type of connection does not have the feature. Sessions, client-side transactions and live queries need a WebSocket, so an HTTP connection raises this error for them. An embedded connection raises it for sessions, transactions, live queries, health(), export(), export_to() and import_().

from surrealdb import Surreal, UnsupportedFeatureError

with Surreal("http://localhost:8000") as db:
    db.signin({"username": "root", "password": "secret"})

    try:
        session = db.new_session()
    except UnsupportedFeatureError as error:
        print(error)
Output
Multi-session and client-side transactions are only supported for WebSocket connections

Extends: UnsupportedFeatureError

The version of the server does not have the feature, such as sessions on SurrealDB 2.x. The SDK raises it before it sends anything, from the version that the server reported to the connection. Code that catches UnsupportedFeatureError also catches this class. To check first, call db.is_feature_supported().

Syntax
UnavailableFeatureError(feature, version, since)
PropertyTypeDescription
featurestrThe name of the feature, such as "sessions"
versionstrThe version of the server, such as "2.7.0"
sincestr | NoneThe first SurrealDB version with the feature, such as "3.0.0", or None when the server is too new for the feature rather than too old
Message on SurrealDB 2.7.0
sessions needs SurrealDB 3.0.0 or later, but this server is 2.7.0. Upgrade the server, or avoid this feature on this connection.

Extends: SurrealError

The version of the server is outside the range that the SDK supports. That range is SurrealDB 2.x, 3.x and 4.x, from MINIMUM_VERSION up to, but not including, MAXIMUM_VERSION. Both constants are exported from surrealdb. A WebSocket connection checks the version when the socket opens, and an HTTP connection before its first request. Pre-release and nightly builds count as the release they lead up to. Pass version_check=False to the connection to connect anyway.

Syntax
UnsupportedVersionError(version, minimum, maximum)
PropertyTypeDescription
versionstrThe version of the server
minimumstrThe lowest supported version
maximumstrThe first version that is not supported

Extends: SurrealError

Surreal() and AsyncSurreal() do not know the scheme of the URL. It is also raised for an embedded URL, such as mem://, when the surrealdb[embedded] package is not installed, and the message names the package to install.

Syntax
UnsupportedEngineError(url)
PropertyTypeDescription
urlstrThe URL that was given
from surrealdb import Surreal, UnsupportedEngineError

try:
    db = Surreal("ftp://localhost:8000")
except UnsupportedEngineError as error:
    print(error.url)
Output
ftp://localhost:8000

Extends: SurrealError

A URL with a known scheme that cannot be parsed, such as one with a port out of range, a port that is not a number, or an IPv6 address without its closing bracket.

from surrealdb import InvalidUrlError, Surreal

try:
    db = Surreal("ws://localhost:99999")
except InvalidUrlError as error:
    print(error)
Output
Could not parse URL 'ws://localhost:99999': Port out of range 0-65535

Extends: SurrealError

Statements in an import_() failed. The other statements were applied. The message lists the first three failures.

Syntax
ImportFailedError(failures)
PropertyTypeDescription
failureslist[ServerError]The error of each statement that failed, in order
Sample message
1 statement(s) in the import failed: Database record `person:tobie` already exists

Extends: SurrealError

The SDK could not read an answer of the server: a response that does not decode, or a value that is not one SurrealDB sends. Mapping records with into= also raises it when a record has a field that the model does not accept.

Extends: SurrealError

A record id given as text that the SDK cannot use: a StringRecordId without a :, a StringRecordId that names a range such as "person:1..3", or text without a : given to RecordID.parse().

Extends: SurrealError

Text that Duration.parse() cannot read. It takes only parts of the form <digits><unit>, such as "1h30m", so "1.5s", "-1s" and "1H" raise this error.

Extends: SurrealError

Geometry data that is not valid, such as a ring of a GeometryPolygon with fewer than four points or with a last point that differs from its first.

Extends: SurrealError

A table or record id string that is not valid. No method of a connection raises it in SDK 3.0, because a plain string is always a table name. It stays exported, so code that catches it still runs.

The kinds that the server gives its errors, as string constants to compare with ServerError.kind or to pass to has_kind() and find_cause().

from surrealdb import ErrorKind
ConstantValueException class
ErrorKind.VALIDATION"Validation"ValidationError
ErrorKind.CONFIGURATION"Configuration"ConfigurationError
ErrorKind.THROWN"Thrown"ThrownError
ErrorKind.QUERY"Query"QueryError
ErrorKind.SERIALIZATION"Serialization"SerializationError
ErrorKind.NOT_ALLOWED"NotAllowed"NotAllowedError
ErrorKind.NOT_FOUND"NotFound"NotFoundError
ErrorKind.ALREADY_EXISTS"AlreadyExists"AlreadyExistsError
ErrorKind.CONNECTION"Connection"ServerError
ErrorKind.INTERNAL"Internal"InternalError

The details of a server error name the reason within its kind, as {"kind": ..., "details": ...}. These classes hold the reasons as constants. The value of each constant is the reason as the server sends it, in CamelCase: QueryDetailKind.TRANSACTION_CONFLICT is "TransactionConflict".

ClassReasons withinConstants
ValidationDetailKindValidationPARSE, INVALID_REQUEST, INVALID_PARAMS, NAMESPACE_EMPTY, DATABASE_EMPTY, INVALID_PARAMETER, INVALID_CONTENT, INVALID_MERGE
ConfigurationDetailKindConfigurationLIVE_QUERY_NOT_SUPPORTED, BAD_LIVE_QUERY_CONFIG, BAD_GRAPHQL_CONFIG
QueryDetailKindQueryNOT_EXECUTED, TIMED_OUT, CANCELLED, TRANSACTION_CONFLICT
SerializationDetailKindSerializationSERIALIZATION, DESERIALIZATION
NotAllowedDetailKindNotAllowedSCRIPTING, AUTH, METHOD, FUNCTION, TARGET
AuthDetailKindThe Auth reason of NotAllowedTOKEN_EXPIRED, SESSION_EXPIRED, INVALID_AUTH, UNEXPECTED_AUTH, MISSING_USER_OR_PASS, NO_SIGNIN_TARGET, INVALID_PASS, TOKEN_MAKING_FAILED, INVALID_SIGNUP, INVALID_ROLE, NOT_ALLOWED
NotFoundDetailKindNotFoundMETHOD, SESSION, TABLE, RECORD, NAMESPACE, DATABASE, TRANSACTION
AlreadyExistsDetailKindAlreadyExistsSESSION, TABLE, RECORD, NAMESPACE, DATABASE
ConnectionDetailKindConnectionUNINITIALISED, ALREADY_CONNECTED

details is None when the server sends no reason, so check it before you read it. A reason without a constant here, such as one added by a newer server, still arrives in details.

from surrealdb import NotFoundDetailKind, NotFoundError, Table

try:
    db.select(Table("post_archive")).execute()
except NotFoundError as error:
    details = error.details or {}
    if details.get("kind") == NotFoundDetailKind.TABLE:
        print("Missing table:", details["details"]["name"])
Output
Missing table: post_archive

A failed sign-in nests one reason in another: {"kind": "Auth", "details": {"kind": "InvalidAuth"}}. The properties of each class, such as NotAllowedError.is_invalid_auth, read the nested reasons for you.

Was this page helpful?