UltipaDocs
Try Playground
  • Introduction
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Data Export
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Data Export
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Data Export
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
    • Quick Start
    • Configuration
    • Connection and Session
    • Executing Queries
    • Graph Management
    • Transactions
    • Data Operations
    • Bulk Import
    • Data Export
    • Health and Administration
    • Response Processing
    • Data Types
    • Error Handling
  1. Docs
  2. /
  3. Ultipa Drivers
  4. /
  5. Node.js

Error Handling

The GQLDB Node.js driver provides a comprehensive set of error classes for handling different failure scenarios. All errors extend the base GqldbError class.

Base Error Class

TypeScript
import { GqldbError } from 'gqldb-nodejs';

class GqldbError extends Error {
  readonly code: number;
  readonly cause?: Error;
}

All GQLDB errors include:

  • message: Human-readable error description
  • name: Error class name
  • code: Numeric error code
  • cause: Original error that caused this error (if applicable)

Error Categories

Configuration Errors

ErrorDescription
NoHostsErrorNo hosts configured in the client
InvalidTimeoutErrorInvalid timeout value specified
TypeScript
import { NoHostsError, InvalidTimeoutError } from 'gqldb-nodejs';

try {
  const config = createConfig({ hosts: [] });
} catch (error) {
  if (error instanceof NoHostsError) {
    console.error('You must configure at least one host');
  }
}

Connection Errors

ErrorDescription
NoConnectionErrorNo connection available
ConnectionClosedErrorConnection has been closed
ConnectionFailedErrorFailed to establish connection
AllHostsFailedErrorAll configured hosts are unreachable
HealthCheckFailedErrorHealth check operation failed
TypeScript
import {
  ConnectionFailedError,
  AllHostsFailedError,
  HealthCheckFailedError
} from 'gqldb-nodejs';

async function connectWithRetry(client: GqldbClient, maxRetries: number) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      await client.login('user', 'pass');
      return true;
    } catch (error) {
      if (error instanceof ConnectionFailedError) {
        console.log(`Connection attempt ${i + 1} failed, retrying...`);
        await sleep(1000 * (i + 1));  // Exponential backoff
      } else if (error instanceof AllHostsFailedError) {
        console.error('All hosts unreachable');
        throw error;
      } else {
        throw error;
      }
    }
  }
  return false;
}

Session Errors

ErrorDescription
NotLoggedInErrorOperation requires authentication
LoginFailedErrorLogin failed (wrong credentials)
LogoutFailedErrorLogout operation failed
SessionExpiredErrorSession has expired
InvalidSessionErrorSession is invalid
TypeScript
import {
  NotLoggedInError,
  LoginFailedError,
  SessionExpiredError
} from 'gqldb-nodejs';

async function ensureLoggedIn(client: GqldbClient) {
  try {
    await client.gql('MATCH (n) RETURN count(n)');
  } catch (error) {
    if (error instanceof NotLoggedInError || error instanceof SessionExpiredError) {
      console.log('Session expired, re-authenticating...');
      await client.login('user', 'pass');
    } else {
      throw error;
    }
  }
}

Transaction Errors

ErrorDescription
NoTransactionErrorNo active transaction
TransactionFailedErrorTransaction operation failed
TransactionNotFoundErrorTransaction not found (may have timed out)
TransactionAlreadyOpenErrorA transaction is already open
TypeScript
import {
  TransactionFailedError,
  TransactionNotFoundError
} from 'gqldb-nodejs';

async function safeTransaction(client: GqldbClient, fn: (txId: number) => Promise<void>) {
  try {
    await client.withTransaction('myGraph', fn);
  } catch (error) {
    if (error instanceof TransactionFailedError) {
      console.error('Transaction failed:', error.message);
    } else if (error instanceof TransactionNotFoundError) {
      console.error('Transaction timed out before completion');
    } else {
      throw error;
    }
  }
}

Query Errors

ErrorDescription
QueryFailedErrorQuery execution failed
QueryTimeoutErrorQuery exceeded timeout
InvalidQueryErrorQuery syntax is invalid
EmptyQueryErrorQuery string is empty
TypeScript
import {
  QueryFailedError,
  QueryTimeoutError,
  InvalidQueryError,
  EmptyQueryError
} from 'gqldb-nodejs';

async function executeQuery(client: GqldbClient, query: string) {
  try {
    return await client.gql(query);
  } catch (error) {
    if (error instanceof EmptyQueryError) {
      console.error('Query cannot be empty');
    } else if (error instanceof InvalidQueryError) {
      console.error('Syntax error:', error.message);
    } else if (error instanceof QueryTimeoutError) {
      console.error('Query timed out - try adding LIMIT or optimizing');
    } else if (error instanceof QueryFailedError) {
      console.error('Query failed:', error.message);
    } else {
      throw error;
    }
    return null;
  }
}

Graph Errors

ErrorDescription
GraphNotFoundErrorGraph does not exist
GraphExistsErrorGraph already exists
CreateGraphFailedErrorFailed to create graph
DropGraphFailedErrorFailed to drop graph
TypeScript
import {
  GraphNotFoundError,
  GraphExistsError,
  CreateGraphFailedError
} from 'gqldb-nodejs';

async function ensureGraph(client: GqldbClient, graphName: string) {
  try {
    await client.getGraphInfo(graphName);
    console.log(`Graph ${graphName} exists`);
  } catch (error) {
    if (error instanceof GraphNotFoundError) {
      try {
        await client.createGraph(graphName);
        console.log(`Created graph ${graphName}`);
      } catch (createError) {
        if (createError instanceof GraphExistsError) {
          // Race condition: another process created it
          console.log(`Graph ${graphName} was created by another process`);
        } else if (createError instanceof CreateGraphFailedError) {
          console.error('Failed to create graph:', createError.message);
          throw createError;
        }
      }
    } else {
      throw error;
    }
  }
}

Data Errors

ErrorDescription
InsertFailedErrorInsert operation failed
DeleteFailedErrorDelete operation failed
ExportFailedErrorExport operation failed
TypeScript
import { InsertFailedError, DeleteFailedError } from 'gqldb-nodejs';

async function safeInsert(client: GqldbClient, nodes: NodeData[]) {
  try {
    const result = await client.insertNodes('myGraph', nodes);
    return result;
  } catch (error) {
    if (error instanceof InsertFailedError) {
      console.error('Insert failed:', error.message);
      // Log the failed nodes for retry
      console.error('Failed nodes:', nodes.map(n => n.id));
    }
    throw error;
  }
}

Type Errors

ErrorDescription
InvalidTypeErrorInvalid type specified
TypeConversionErrorFailed to convert type
UnsupportedTypeErrorType is not supported
TypeScript
import { TypeConversionError, UnsupportedTypeError } from 'gqldb-nodejs';

function processValue(row: Row, index: number) {
  try {
    return row.getNumber(index);
  } catch (error) {
    if (error instanceof TypeConversionError) {
      console.warn(`Value at ${index} is not a number, using string`);
      return row.getString(index);
    }
    throw error;
  }
}

Error Handling Patterns

Comprehensive Try-Catch

TypeScript
import { GqldbError } from 'gqldb-nodejs';

async function handleAllErrors(client: GqldbClient) {
  try {
    await client.login('user', 'pass');
    await client.gql('MATCH (n) RETURN n');
  } catch (error) {
    if (error instanceof GqldbError) {
      // All driver errors
      console.error(`GQLDB Error [${error.name}]: ${error.message}`);
      if (error.cause) {
        console.error('Caused by:', error.cause);
      }
    } else if (error instanceof Error) {
      // Other JavaScript errors
      console.error('Unexpected error:', error.message);
    } else {
      console.error('Unknown error:', error);
    }
  }
}

Error Recovery with Retry

TypeScript
async function withRetry<T>(
  operation: () => Promise<T>,
  maxRetries: number = 3,
  retryableErrors: Array<new (...args: any[]) => GqldbError> = []
): Promise<T> {
  let lastError: Error | undefined;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error as Error;

      const isRetryable = retryableErrors.some(
        ErrorClass => error instanceof ErrorClass
      );

      if (!isRetryable || attempt === maxRetries) {
        throw error;
      }

      console.log(`Attempt ${attempt} failed, retrying...`);
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }

  throw lastError;
}

// Usage
import { ConnectionFailedError, QueryTimeoutError } from 'gqldb-nodejs';

const result = await withRetry(
  () => client.gql('MATCH (n) RETURN n LIMIT 100'),
  3,
  [ConnectionFailedError, QueryTimeoutError]
);

Graceful Degradation

TypeScript
async function getDataWithFallback(client: GqldbClient) {
  try {
    // Try the main query
    return await client.gql('MATCH (n:User) RETURN n');
  } catch (error) {
    if (error instanceof QueryTimeoutError) {
      // Fall back to a simpler query
      console.warn('Full query timed out, using limited query');
      return await client.gql('MATCH (n:User) RETURN n LIMIT 100');
    }
    throw error;
  }
}

Cleanup on Error

TypeScript
async function transactionWithCleanup(client: GqldbClient) {
  let tx: Transaction | undefined;

  try {
    tx = await client.beginTransaction('myGraph');

    await client.gql('INSERT ...', { transactionId: tx.id });
    await client.gql('INSERT ...', { transactionId: tx.id });

    await client.commit(tx.id);
    tx = undefined;  // Transaction completed

  } finally {
    if (tx) {
      // Transaction was started but not committed
      try {
        await client.rollback(tx.id);
      } catch (rollbackError) {
        console.error('Rollback failed:', rollbackError);
      }
    }
  }
}

Complete Example

TypeScript
import {
  GqldbClient,
  createConfig,
  GqldbError,
  LoginFailedError,
  QueryFailedError,
  QueryTimeoutError,
  GraphNotFoundError,
  TransactionFailedError
} from 'gqldb-nodejs';

async function main() {
  const client = new GqldbClient(createConfig({
    hosts: ['192.168.1.100:9000'],
    timeout: 30000
  }));

  try {
    // Login with error handling
    try {
      await client.login('admin', 'password');
      console.log('Logged in successfully');
    } catch (error) {
      if (error instanceof LoginFailedError) {
        console.error('Invalid credentials');
        process.exit(1);
      }
      throw error;
    }

    // Ensure graph exists
    const graphName = 'errorDemo';
    try {
      await client.getGraphInfo(graphName);
    } catch (error) {
      if (error instanceof GraphNotFoundError) {
        await client.createGraph(graphName);
        console.log('Created graph');
      } else {
        throw error;
      }
    }

    await client.useGraph(graphName);

    // Transaction with error handling
    try {
      await client.withTransaction(graphName, async (txId) => {
        await client.gql(
          'INSERT (n:User {_id: "u1", name: "Alice"})',
          { transactionId: txId }
        );
        // Simulate potential error
        if (Math.random() < 0.3) {
          throw new Error('Random failure for demo');
        }
      });
      console.log('Transaction succeeded');
    } catch (error) {
      if (error instanceof TransactionFailedError) {
        console.error('Transaction failed, changes rolled back');
      } else {
        console.error('Error during transaction:', (error as Error).message);
      }
    }

    // Query with timeout handling
    try {
      const response = await client.gql(
        'MATCH (n) RETURN n',
        { timeout: 5000 }
      );
      console.log(`Found ${response.rowCount} results`);
    } catch (error) {
      if (error instanceof QueryTimeoutError) {
        console.warn('Query timed out, trying with limit');
        const limited = await client.gql('MATCH (n) RETURN n LIMIT 10');
        console.log(`Found ${limited.rowCount} results (limited)`);
      } else if (error instanceof QueryFailedError) {
        console.error('Query error:', error.message);
      } else {
        throw error;
      }
    }

    // Cleanup
    await client.dropGraph(graphName, true);

  } catch (error) {
    // Catch-all for unexpected errors
    if (error instanceof GqldbError) {
      console.error(`GQLDB Error: [${error.name}] ${error.message}`);
      if (error.cause) {
        console.error('Root cause:', error.cause.message);
      }
    } else {
      console.error('Unexpected error:', error);
    }
    process.exit(1);

  } finally {
    await client.close();
    console.log('Client closed');
  }
}

main();