• Start

Languages

/

JavaScript

/

API Reference

/

Errors

Errors

Error classes for handling different types of failures in the SDK.

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 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);
}
}

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');
}
}

Thrown when an HTTP connection fails.

Properties:

  • status (number) - HTTP status code

  • statusText (string) - HTTP status text

  • buffer (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}`);
}
}

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');
}
}

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);
}
}

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`);
}
}

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');
}
});

Thrown when a reconnect iterator fails to iterate.

Message: "The reconnect iterator failed to iterate"

Server errors represent structured errors returned by the SurrealDB server. They form a class hierarchy rooted at ServerError, which replaces the former ResponseError class.

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;

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 server

  • cause (ServerError | undefined) - Optional inner ServerError forming 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);
}
}
}

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 error

  • parameterName (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);
}
}
}

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

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);
}
}

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 out

  • isCancelled (boolean) - True if the query was cancelled

  • timeout ({ 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');
}
}
}

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)

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 expired

  • isInvalidAuth (boolean) - True if authentication credentials are invalid

  • isScriptingBlocked (boolean) - True if scripting is blocked

  • methodName (string | undefined) - The method name that is not allowed, if applicable

  • functionName (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');
}
}
}

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 found

  • recordId (string | undefined) - The record ID that was not found

  • methodName (string | undefined) - The RPC method name that was not found

  • namespaceName (string | undefined) - The namespace name that was not found

  • databaseName (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`);
}
}
}

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 exists

  • tableName (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`);
}
}
}

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 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';

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);
}
}

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);
}
}

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' });
}
}

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);
}
}

Thrown when the connected SurrealDB version is not supported by the SDK.

Properties:

  • version (string) - The unsupported version

  • minimum (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}`
);
}
}

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);
}
}

Thrown when one or more event subscribers throw an error during publication.

Properties:

  • causes (unknown[]) - The errors thrown by subscribers

  • message (string) - Summary message including the cause messages

Example:

db.subscribe('auth', () => {
throw new Error('Handler failed');
});
// When the event fires, a PublishError may be emitted

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: <date>". 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);
}
}

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`);
}
}

Thrown when attempting to use a feature not available in the connected SurrealDB version.

Properties:

  • feature (Feature) - The unavailable feature

  • version (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}`);
}
}

Thrown when a user-defined API call fails.

Properties:

  • path (string) - The API path that was invoked

  • method (string) - The HTTP method used

  • response (ApiResponse) - The error response from the API (includes body?, 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}`);
}
}

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');
}
}

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);
}
}

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);
}
}

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);
}
}

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);
}
}
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);
}
}
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);
}
}
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'))
);
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);
}
});

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
}

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();
}

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,
});
}
}

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
}

Source: errors.ts

Was this page helpful?