The SDK defines specific error classes for different failure scenarios. All error classes extend the base SurrealError class, allowing you to catch and handle specific error types.
Base error
SurrealError
Base class for all SDK errors.
Extends: Error
Example:
try {
await db.select(new RecordId('users', 'john'));
} catch (error) {
if (error instanceof SurrealError) {
console.error('SDK error:', error.message);
}
}Connection errors
ConnectionUnavailableError
Thrown when attempting an operation without an active connection.
Message: "You must be connected to a SurrealDB instance before performing this operation"
Example:
const db = new Surreal();
try {
await db.select(new Table('users')); // Not connected
} catch (error) {
if (error instanceof ConnectionUnavailableError) {
console.error('Not connected to database');
await db.connect('ws://localhost:8000');
}
} HttpConnectionError
Thrown when an HTTP connection fails.
Properties:
status(number) - HTTP status codestatusText(string) - HTTP status textbuffer(ArrayBuffer) - Response buffer
Example:
try {
await db.connect('http://localhost:8000/rpc');
} catch (error) {
if (error instanceof HttpConnectionError) {
console.error(`HTTP ${error.status}: ${error.statusText}`);
}
} CallTerminatedError
Thrown when a call is terminated because the connection was closed.
Message: "The call has been terminated because the connection was closed"
Example:
try {
const promise = db.query('SELECT SLEEP(10s)');
await db.close(); // Close connection while query running
await promise; // Will throw CallTerminatedError
} catch (error) {
if (error instanceof CallTerminatedError) {
console.error('Connection closed during operation');
}
} UnexpectedConnectionError
Thrown when an unexpected connection error occurs.
Properties:
cause(unknown) - The underlying error cause
Example:
try {
await db.connect('ws://invalid:8000');
} catch (error) {
if (error instanceof UnexpectedConnectionError) {
console.error('Connection error:', error.cause);
}
} UnsupportedEngineError
Thrown when attempting to use an unsupported or unconfigured engine.
Properties:
engine(string) - The unsupported engine name
Example:
try {
await db.connect('custom://localhost:8000');
} catch (error) {
if (error instanceof UnsupportedEngineError) {
console.error(`Engine "${error.engine}" is not supported`);
}
}Reconnection errors
ReconnectExhaustionError
Thrown when reconnect attempts have been exhausted.
Message: "The reconnect attempts have been exhausted"
Example:
db.subscribe('error', (error) => {
if (error instanceof ReconnectExhaustionError) {
console.error('Failed to reconnect after multiple attempts');
}
}); ReconnectIterationError
Thrown when a reconnect iterator fails to iterate.
Message: "The reconnect iterator failed to iterate"
Server errors
Server errors represent structured errors returned by the SurrealDB server. They form a class hierarchy rooted at ServerError, which replaces the former ResponseError class.
ErrorKind
Known error kinds returned by the SurrealDB server. Use these constants for matching against ServerError.kind.
const ErrorKind = {
Validation: "Validation",
Configuration: "Configuration",
Thrown: "Thrown",
Query: "Query",
Serialization: "Serialization",
NotAllowed: "NotAllowed",
NotFound: "NotFound",
AlreadyExists: "AlreadyExists",
Connection: "Connection",
Internal: "Internal",
} as const; ServerError
Base class for all errors originating from the SurrealDB server. Each error carries structured information about the failure.
Extends: SurrealError
Properties:
kind(string) - The error category (e.g."NotAllowed","NotFound")code(number) - Legacy JSON-RPC numeric error code (0 when unavailable)details(ErrorDetail | undefined) - Kind-specific structured details from the servercause(ServerError | undefined) - Optional innerServerErrorforming a recursive error chain
Example:
try {
await db.query('INVALID QUERY');
} catch (error) {
if (error instanceof ServerError) {
console.error(`Server error [${error.kind}]: ${error.message}`);
if (error.cause) {
console.error('Caused by:', error.cause.message);
}
}
} ValidationError
Thrown on validation failures such as parse errors, invalid requests, or invalid parameters.
Extends: ServerError (kind: "Validation")
Convenience getters:
isParseError(boolean) - True if this is a SurrealQL parse errorparameterName(string | undefined) - The name of the invalid parameter, if applicable
Example:
try {
await db.query('SELEC * FROM users'); // Typo
} catch (error) {
if (error instanceof ValidationError) {
if (error.isParseError) {
console.error('SurrealQL syntax error:', error.message);
}
}
} ConfigurationError
Thrown when a feature or configuration is not supported by the server (e.g. live queries, GraphQL).
Extends: ServerError (kind: "Configuration")
Convenience getters:
isLiveQueryNotSupported(boolean) - True if live queries are not supported by the server configuration
ThrownError
Thrown when a user-thrown error is raised via THROW in SurrealQL.
Extends: ServerError (kind: "Thrown")
Example:
try {
await db.query('THROW "something went wrong"');
} catch (error) {
if (error instanceof ThrownError) {
console.error('SurrealQL THROW:', error.message);
}
} QueryError
Thrown on query execution failures such as timeouts, cancellations, or skipped statements.
Extends: ServerError (kind: "Query")
Convenience getters:
isNotExecuted(boolean) - True if the query was not executed (e.g. due to a prior error in the batch)isTimedOut(boolean) - True if the query timed outisCancelled(boolean) - True if the query was cancelledtimeout({ secs: number, nanos: number } | undefined) - The timeout duration, if this is a timeout error
Example:
try {
await db.query('SELECT * FROM heavy_table TIMEOUT 1s');
} catch (error) {
if (error instanceof QueryError) {
if (error.isTimedOut) {
console.error('Query timed out after', error.timeout?.secs, 'seconds');
} else if (error.isNotExecuted) {
console.error('Query was not executed');
}
}
} SerializationError
Thrown on serialization or deserialization failures.
Extends: ServerError (kind: "Serialization")
Convenience getters:
isDeserialization(boolean) - True if this is a deserialization error (as opposed to serialization)
NotAllowedError
Thrown when a permission is denied, a method is not allowed, or a function/scripting call is blocked.
Extends: ServerError (kind: "NotAllowed")
Convenience getters:
isTokenExpired(boolean) - True if the auth token has expiredisInvalidAuth(boolean) - True if authentication credentials are invalidisScriptingBlocked(boolean) - True if scripting is blockedmethodName(string | undefined) - The method name that is not allowed, if applicablefunctionName(string | undefined) - The function name that is not allowed, if applicable
Example:
try {
await db.query('SELECT * FROM protected_table');
} catch (error) {
if (error instanceof NotAllowedError) {
if (error.isTokenExpired) {
console.error('Token expired, re-authenticate');
} else if (error.isInvalidAuth) {
console.error('Invalid credentials');
}
}
} NotFoundError
Thrown when a resource is not found (table, record, namespace, method, etc.).
Extends: ServerError (kind: "NotFound")
Convenience getters:
tableName(string | undefined) - The table name that was not foundrecordId(string | undefined) - The record ID that was not foundmethodName(string | undefined) - The RPC method name that was not foundnamespaceName(string | undefined) - The namespace name that was not founddatabaseName(string | undefined) - The database name that was not found
Example:
try {
await db.query('SELECT * FROM nonexistent');
} catch (error) {
if (error instanceof NotFoundError) {
if (error.tableName) {
console.error(`Table "${error.tableName}" does not exist`);
} else if (error.recordId) {
console.error(`Record "${error.recordId}" not found`);
}
}
} AlreadyExistsError
Thrown when a duplicate resource is encountered (record, table, namespace, etc.).
Extends: ServerError (kind: "AlreadyExists")
Convenience getters:
recordId(string | undefined) - The record ID that already existstableName(string | undefined) - The table name that already exists
Example:
try {
await db.create(new RecordId('users', 'john'), { name: 'John' });
} catch (error) {
if (error instanceof AlreadyExistsError) {
if (error.recordId) {
console.error(`Record "${error.recordId}" already exists`);
}
}
} InternalError
Thrown on unexpected or unknown internal server errors. Also used as the fallback for unrecognized kind strings from newer servers.
Extends: ServerError (kind: "Internal")
ResponseError (Deprecated)
ResponseError is a deprecated alias for ServerError. It exists for backward compatibility.
// ResponseError is the same as ServerError
import { ResponseError } from 'surrealdb';
// Equivalent to:
import { ServerError } from 'surrealdb'; UnexpectedServerResponseError
Thrown when the server returns a response in an unexpected format.
Properties:
response(unknown) - The unexpected response received
Example:
try {
await db.query(complexQuery);
} catch (error) {
if (error instanceof UnexpectedServerResponseError) {
console.error('Unexpected response:', error.response);
}
}Authentication errors
AuthenticationError
Thrown when authentication fails.
Message: "Authentication did not succeed"
Properties:
cause(unknown) - The underlying error cause
Example:
try {
await db.signin({
username: 'user',
password: 'wrongpassword'
});
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.cause);
}
} MissingNamespaceDatabaseError
Thrown when a namespace and/or database is required but not selected.
Message: "There is no namespace and/or database selected"
Example:
const db = new Surreal();
await db.connect('ws://localhost:8000');
try {
await db.select(new Table('users')); // No namespace/database set
} catch (error) {
if (error instanceof MissingNamespaceDatabaseError) {
await db.use({ namespace: 'main', database: 'main' });
}
}Live query errors
LiveSubscriptionError
Thrown when a live subscription fails to listen.
Constructor: new LiveSubscriptionError(messageOrCause?: string | unknown)
When called with a string, it is used as the error message. When called with any other value (or no argument), the default message "Live subscription failed to listen" is used and the argument is set as cause.
Example:
try {
const subscription = await db.live(new Table('users'));
} catch (error) {
if (error instanceof LiveSubscriptionError) {
console.error('Live query failed:', error.cause);
}
}Version errors
UnsupportedVersionError
Thrown when the connected SurrealDB version is not supported by the SDK.
Properties:
version(string) - The unsupported versionminimum(string) - Minimum supported version (inclusive)maximum(string) - Maximum supported version (exclusive)
Example:
try {
await db.connect('ws://localhost:8000', {
versionCheck: true
});
} catch (error) {
if (error instanceof UnsupportedVersionError) {
console.error(
`Version ${error.version} not supported. ` +
`Requires: >= ${error.minimum} < ${error.maximum}`
);
}
}Expression errors
ExpressionError
Thrown when a SurrealQL expression fails to compile or execute.
Constructor: new ExpressionError(messageOrCause?: string | unknown)
When called with a string, it is used as the error message. When called with any other value (or no argument), the default message "Failed to parse invalid expression" is used and the argument is set as cause.
Example:
try {
const invalid = expr(() => {
throw new Error('Invalid expression');
});
} catch (error) {
if (error instanceof ExpressionError) {
console.error('Expression error:', error.message);
}
}Event errors
PublishError
Thrown when one or more event subscribers throw an error during publication.
Properties:
causes(unknown[]) - The errors thrown by subscribersmessage(string) - Summary message including the cause messages
Example:
db.subscribe('auth', () => {
throw new Error('Handler failed');
});
// When the event fires, a PublishError may be emittedDate and time errors
InvalidDateError
Thrown when a parsed date or datetime is invalid.
Constructor: new InvalidDateError(dateOrMessage: Date | string)
When called with a `Date`, the message is `"The provided date is invalid: "`. When called with a string, the string is used directly as the error message.
Example:
try {
new DateTime('not-a-date');
} catch (error) {
if (error instanceof InvalidDateError) {
console.error('Invalid date:', error.message);
}
}Feature errors
UnsupportedFeatureError
Thrown when attempting to use a feature not supported by the configured engine.
Properties:
feature(Feature) - The unsupported feature
Example:
try {
await db.live(new Table('users')); // Not supported by engine
} catch (error) {
if (error instanceof UnsupportedFeatureError) {
console.error(`Feature "${error.feature.name}" not supported`);
}
} UnavailableFeatureError
Thrown when attempting to use a feature not available in the connected SurrealDB version.
Properties:
feature(Feature) - The unavailable featureversion(string) - The connected SurrealDB version
Example:
try {
await db.connect('http://localhost:8000/rpc');
await db.live(new Table('users'));
} catch (error) {
if (error instanceof UnavailableFeatureError) {
console.error(`Feature "${error.feature.name}" not available in version ${error.version}`);
}
}API errors
UnsuccessfulApiError
Thrown when a user-defined API call fails.
Properties:
path(string) - The API path that was invokedmethod(string) - The HTTP method usedresponse(ApiResponse) - The error response from the API (includesbody?,headers?,status?)message(string) - Human-readable message (inherited from Error; includes path, method, and status)
Example:
try {
await db.api().get('/users/999');
} catch (error) {
if (error instanceof UnsuccessfulApiError) {
console.error(`API error: ${error.message}`);
console.error(`Status: ${error.response.status}`);
}
}Session errors
InvalidSessionError
Thrown when attempting to use an invalid or disposed session.
Properties:
session(Session) - The invalid session identifier
Example:
const session = await db.newSession();
await session.closeSession();
try {
await session.select(new Table('users')); // Session closed
} catch (error) {
if (error instanceof InvalidSessionError) {
console.error('Session is no longer valid');
}
}Value validation errors
InvalidRecordIdError
Thrown when a RecordId or RecordIdRange is constructed with invalid parts.
Example:
try {
new RecordId('', 'id'); // Invalid table name
} catch (error) {
if (error instanceof InvalidRecordIdError) {
console.error('Invalid record ID:', error.message);
}
} InvalidDurationError
Thrown when a Duration string cannot be parsed or a duration operation is invalid.
Example:
try {
new Duration('not-a-duration');
} catch (error) {
if (error instanceof InvalidDurationError) {
console.error('Invalid duration:', error.message);
}
} InvalidDecimalError
Thrown when a Decimal operation fails (e.g. division by zero, invalid input).
Example:
try {
new Decimal('not-a-number');
} catch (error) {
if (error instanceof InvalidDecimalError) {
console.error('Invalid decimal:', error.message);
}
} InvalidTableError
Thrown when a Table or StringRecordId is constructed with an invalid value.
Example:
try {
new Table(''); // Empty table name
} catch (error) {
if (error instanceof InvalidTableError) {
console.error('Invalid table:', error.message);
}
}Error handling patterns
Basic error handling
try {
const result = await db.select(new Table('users'));
} catch (error) {
if (error instanceof SurrealError) {
// Handle all SDK errors
console.error('SDK error:', error.message);
} else {
// Handle other errors
console.error('Unexpected error:', error);
}
}Specific error handling
try {
await db.connect('ws://localhost:8000');
await db.use({ namespace: 'main', database: 'main' });
await db.signin({ username: 'user', password: 'pass' });
} catch (error) {
if (error instanceof ConnectionUnavailableError) {
console.error('Cannot connect to database');
} else if (error instanceof AuthenticationError) {
console.error('Invalid credentials');
} else if (error instanceof UnsupportedVersionError) {
console.error('Database version incompatible');
} else {
console.error('Unknown error:', error);
}
}Error recovery
async function executeWithRetry(fn: () => Promise<any>, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (error instanceof ConnectionUnavailableError) {
// Reconnect and retry
await db.connect('ws://localhost:8000');
continue;
} else if (error instanceof ServerError && attempt < maxRetries - 1) {
// Retry on server errors
continue;
}
throw error;
}
}
}
const result = await executeWithRetry(() =>
db.select(new Table('users'))
);Global error handler
db.subscribe('error', (error) => {
if (error instanceof ReconnectExhaustionError) {
// Handle reconnection failure
notifyUser('Connection lost. Please check your network.');
} else if (error instanceof UnexpectedConnectionError) {
// Log unexpected errors
logger.error('Unexpected connection error:', error.cause);
}
});Best practices
1. Catch specific errors
Handle specific error types for better error recovery:
// Good: Specific handling
try {
await operation();
} catch (error) {
if (error instanceof AuthenticationError) {
redirectToLogin();
} else if (error instanceof ConnectionUnavailableError) {
showConnectionError();
}
}
// Avoid: Generic handling
try {
await operation();
} catch (error) {
console.error(error); // Lost context
}2. Use type guards
TypeScript type guards provide better type safety:
function isConnectionError(error: unknown): error is ConnectionUnavailableError {
return error instanceof ConnectionUnavailableError;
}
if (isConnectionError(error)) {
// TypeScript knows error is ConnectionUnavailableError
await reconnect();
}3. Log error details
Include error details in logs for debugging:
catch (error) {
if (error instanceof ServerError) {
logger.error('Query failed', {
kind: error.kind,
code: error.code,
message: error.message,
details: error.details,
});
}
}4. Clean up on error
Ensure resources are cleaned up even when errors occur:
const session = await db.newSession();
try {
await session.select(new Table('users'));
} finally {
await session.closeSession(); // Always clean up
}See also
Core Classes - Classes that may throw errors
Surreal - Connection methods that may throw errors
SurrealSession - Session methods that may throw errors
Source: errors.ts