CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sequelize

Promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Amazon Redshift and Snowflake's Data Cloud with solid transaction support, relations, eager and lazy loading, read replication and more

Pending
Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Comprehensive error hierarchy for handling database-specific errors, validation failures, and connection issues.

Capabilities

Base Error Classes

Foundation error classes that other Sequelize errors extend from.

/**
 * Base error class for all Sequelize errors
 */
class BaseError extends Error {
  /** Error name */
  name: string;
  /** Error message */
  message: string;
  /** Stack trace */
  stack?: string;
}

/**
 * Database-related errors with SQL context
 */
class DatabaseError extends BaseError {
  /** SQL query that caused the error */
  sql?: string;
  /** Query parameters */
  parameters?: any[];
  /** Original database error */
  original?: Error;
  /** Error number from database */
  errno?: number;
  /** SQL state code */
  sqlState?: string;
  /** SQL message from database */
  sqlMessage?: string;
}

Validation Errors

Errors related to model validation and data integrity.

/**
 * Model validation error containing multiple validation failures
 */
class ValidationError extends BaseError {
  /** Array of individual validation errors */
  errors: ValidationErrorItem[];
  /** Fields that failed validation */
  fields: { [field: string]: ValidationErrorItem[] };
}

/**
 * Individual validation error for a specific field
 */
class ValidationErrorItem {
  /** Error message */
  message: string;
  /** Validation type */
  type: string;
  /** Field path */
  path: string;
  /** Field value that failed */
  value: any;
  /** Validator origin */
  origin: string;
  /** Model instance */
  instance?: Model;
  /** Validator key */
  validatorKey?: string;
  /** Validator name */
  validatorName?: string;
  /** Validator arguments */
  validatorArgs?: any[];
}

/**
 * Unique constraint violation error
 */
class UniqueConstraintError extends ValidationError {
  /** Fields that caused the constraint violation */
  fields: string[];
  /** Values that caused the violation */
  value: any;
  /** Index name */
  index: string;
  /** Relation name */
  reltype?: string;
}

/**
 * Foreign key constraint violation error
 */
class ForeignKeyConstraintError extends DatabaseError {
  /** Referenced table */
  table: string;
  /** Referenced fields */
  fields: string[];
  /** Referenced value */
  value: any;
  /** Constraint index */
  index: string;
  /** Relation type */
  reltype?: string;
}

/**
 * Exclusion constraint violation error
 */
class ExclusionConstraintError extends DatabaseError {
  /** Constraint fields */
  fields: string[];
  /** Constraint table */
  table: string;
  /** Constraint index */
  constraint: string;
}

Usage Examples:

try {
  await User.create({
    email: 'invalid-email',
    age: -5
  });
} catch (error) {
  if (error instanceof ValidationError) {
    console.log('Validation failed:');
    error.errors.forEach(err => {
      console.log(`- ${err.path}: ${err.message}`);
    });
    
    // Check specific field errors
    if (error.fields.email) {
      console.log('Email validation failed');
    }
  }
}

// Handle unique constraint violations
try {
  await User.create({
    email: 'existing@example.com'  // Already exists
  });
} catch (error) {
  if (error instanceof UniqueConstraintError) {
    console.log(`Duplicate value for fields: ${error.fields.join(', ')}`);
    console.log(`Constraint: ${error.index}`);
  }
}

// Handle foreign key violations
try {
  await Post.create({
    title: 'My Post',
    userId: 999  // Non-existent user
  });
} catch (error) {
  if (error instanceof ForeignKeyConstraintError) {
    console.log(`Foreign key violation on table: ${error.table}`);
    console.log(`Fields: ${error.fields.join(', ')}`);
  }
}

Connection Errors

Errors related to database connectivity and access.

/**
 * Base connection error
 */
class ConnectionError extends BaseError {
  /** Original connection error */
  original?: Error;
}

/**
 * Database access denied
 */
class AccessDeniedError extends ConnectionError {}

/**
 * Connection acquisition timeout
 */
class ConnectionAcquireTimeoutError extends ConnectionError {}

/**
 * Connection refused by database
 */
class ConnectionRefusedError extends ConnectionError {}

/**
 * Connection timed out
 */
class ConnectionTimedOutError extends ConnectionError {}

/**
 * Database host not found
 */
class HostNotFoundError extends ConnectionError {}

/**
 * Database host not reachable
 */
class HostNotReachableError extends ConnectionError {}

/**
 * Invalid connection configuration
 */
class InvalidConnectionError extends ConnectionError {}

/**
 * Database timeout error
 */
class TimeoutError extends DatabaseError {}

Usage Examples:

try {
  await sequelize.authenticate();
} catch (error) {
  if (error instanceof ConnectionRefusedError) {
    console.log('Database refused connection - check if database is running');
  } else if (error instanceof AccessDeniedError) {
    console.log('Access denied - check credentials');
  } else if (error instanceof HostNotFoundError) {
    console.log('Database host not found - check hostname');
  } else if (error instanceof ConnectionTimedOutError) {
    console.log('Connection timed out - check network or increase timeout');
  }
}

// Handle query timeouts  
try {
  await User.findAll({
    // Long-running query
  });
} catch (error) {
  if (error instanceof TimeoutError) {
    console.log('Query timed out - consider optimizing or increasing timeout');
  }
}

Application Logic Errors

Errors related to application logic and ORM usage.

/**
 * Model instance-related error
 */
class InstanceError extends BaseError {}

/**
 * Association-related error
 */
class AssociationError extends BaseError {}

/**
 * Query-related error
 */
class QueryError extends BaseError {
  /** SQL query */
  sql?: string;
  /** Query parameters */
  parameters?: any[];
}

/**
 * Scope-related error
 */
class SequelizeScopeError extends BaseError {}

/**
 * Eager loading error
 */
class EagerLoadingError extends BaseError {}

/**
 * Empty result error (when expecting results)
 */
class EmptyResultError extends BaseError {}

/**
 * Optimistic locking error
 */
class OptimisticLockError extends BaseError {}

/**
 * Bulk operation error
 */
class BulkRecordError extends BaseError {
  /** Records that failed */
  errors: Error[];
}

/**
 * Multiple errors aggregated
 */
class AggregateError extends BaseError {
  /** Individual errors */
  errors: Error[];
}

Usage Examples:

// Handle empty results
try {
  const user = await User.findOne({
    where: { id: 999 },
    rejectOnEmpty: true  // Throws EmptyResultError if not found
  });
} catch (error) {
  if (error instanceof EmptyResultError) {
    console.log('User not found');
  }
}

// Handle optimistic locking
try {
  const user = await User.findByPk(1);
  user.name = 'Updated';
  await user.save(); // May fail if record was modified
} catch (error) {
  if (error instanceof OptimisticLockError) {
    console.log('Record was modified by another process');
    // Reload and retry
  }
}

// Handle bulk operation errors
try {
  await User.bulkCreate([
    { email: 'user1@example.com' },
    { email: 'invalid-email' },  // Will fail validation
    { email: 'user3@example.com' }
  ]);
} catch (error) {
  if (error instanceof BulkRecordError) {
    console.log(`${error.errors.length} records failed`);
    error.errors.forEach((err, index) => {
      console.log(`Record ${index}: ${err.message}`);
    });
  }
}

Error Handling Patterns

Common patterns for handling Sequelize errors in applications.

// Error type guards
function isSequelizeError(error: any): error is BaseError {
  return error instanceof BaseError;
}

function isValidationError(error: any): error is ValidationError {
  return error instanceof ValidationError;
}

function isConnectionError(error: any): error is ConnectionError {
  return error instanceof ConnectionError;
}

Usage Examples:

// Comprehensive error handling middleware (Express.js example)
function sequelizeErrorHandler(error: any, req: any, res: any, next: any) {
  if (!isSequelizeError(error)) {
    return next(error);
  }

  // Validation errors
  if (error instanceof ValidationError) {
    return res.status(400).json({
      type: 'validation_error',
      message: 'Validation failed',
      errors: error.errors.map(err => ({
        field: err.path,
        message: err.message,
        value: err.value
      }))
    });
  }

  // Unique constraint violations
  if (error instanceof UniqueConstraintError) {
    return res.status(409).json({
      type: 'duplicate_error',
      message: `Duplicate value for: ${error.fields.join(', ')}`,
      fields: error.fields
    });
  }

  // Foreign key violations
  if (error instanceof ForeignKeyConstraintError) {
    return res.status(400).json({
      type: 'reference_error',
      message: 'Invalid reference to related record',
      table: error.table,
      fields: error.fields
    });
  }

  // Connection errors
  if (isConnectionError(error)) {
    console.error('Database connection error:', error);
    return res.status(503).json({
      type: 'database_error',
      message: 'Database temporarily unavailable'
    });
  }

  // Other database errors
  if (error instanceof DatabaseError) {
    console.error('Database error:', error.sql, error.parameters);
    return res.status(500).json({
      type: 'database_error',
      message: 'Internal database error'
    });
  }

  // Generic Sequelize errors
  return res.status(500).json({
    type: 'sequelize_error',
    message: error.message
  });
}

// Retry pattern for connection errors
async function withRetry<T>(
  operation: () => Promise<T>,
  maxRetries: number = 3,
  delay: number = 1000
): Promise<T> {
  let lastError: Error;

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

      // Only retry on connection errors
      if (isConnectionError(error) && attempt < maxRetries) {
        console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        delay *= 2; // Exponential backoff
        continue;
      }

      throw error;
    }
  }

  throw lastError!;
}

// Usage with retry
const user = await withRetry(async () => {
  return await User.findByPk(1);
});

// Validation helper
async function validateAndCreate<T extends Model>(
  model: typeof Model,
  data: any
): Promise<T> {
  try {
    return await model.create(data);
  } catch (error) {
    if (error instanceof ValidationError) {
      // Transform validation errors for client
      const validationErrors = error.errors.reduce((acc, err) => {
        acc[err.path] = err.message;
        return acc;
      }, {} as Record<string, string>);

      throw new Error(JSON.stringify({
        type: 'validation_failed',
        errors: validationErrors
      }));
    }
    throw error;
  }
}

Custom Error Classes

Creating application-specific error classes that extend Sequelize errors.

// Custom business logic errors
class InsufficientFundsError extends BaseError {
  constructor(balance: number, required: number) {
    super(`Insufficient funds: balance ${balance}, required ${required}`);
    this.name = 'InsufficientFundsError';
  }
}

class UserNotActiveError extends BaseError {
  constructor(userId: number) {
    super(`User ${userId} is not active`);
    this.name = 'UserNotActiveError';
  }
}

// Usage in business logic
async function transferFunds(fromUserId: number, toUserId: number, amount: number) {
  return await sequelize.transaction(async (t) => {
    const fromUser = await User.findByPk(fromUserId, { transaction: t });
    const toUser = await User.findByPk(toUserId, { transaction: t });

    if (!fromUser?.isActive) {
      throw new UserNotActiveError(fromUserId);
    }

    if (fromUser.balance < amount) {
      throw new InsufficientFundsError(fromUser.balance, amount);
    }

    // Perform transfer...
  });
}

Install with Tessl CLI

npx tessl i tessl/npm-sequelize

docs

associations.md

data-types.md

database-connection.md

error-handling.md

hooks.md

index.md

model-definition.md

query-operators.md

querying.md

transactions.md

tile.json