or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

associations.mddata-types.mddatabase-connection.mderror-handling.mdhooks.mdindex.mdmodel-definition.mdquery-operators.mdquerying.mdtransactions.md

error-handling.mddocs/

0

# Error Handling

1

2

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

3

4

## Capabilities

5

6

### Base Error Classes

7

8

Foundation error classes that other Sequelize errors extend from.

9

10

```typescript { .api }

11

/**

12

* Base error class for all Sequelize errors

13

*/

14

class BaseError extends Error {

15

/** Error name */

16

name: string;

17

/** Error message */

18

message: string;

19

/** Stack trace */

20

stack?: string;

21

}

22

23

/**

24

* Database-related errors with SQL context

25

*/

26

class DatabaseError extends BaseError {

27

/** SQL query that caused the error */

28

sql?: string;

29

/** Query parameters */

30

parameters?: any[];

31

/** Original database error */

32

original?: Error;

33

/** Error number from database */

34

errno?: number;

35

/** SQL state code */

36

sqlState?: string;

37

/** SQL message from database */

38

sqlMessage?: string;

39

}

40

```

41

42

### Validation Errors

43

44

Errors related to model validation and data integrity.

45

46

```typescript { .api }

47

/**

48

* Model validation error containing multiple validation failures

49

*/

50

class ValidationError extends BaseError {

51

/** Array of individual validation errors */

52

errors: ValidationErrorItem[];

53

/** Fields that failed validation */

54

fields: { [field: string]: ValidationErrorItem[] };

55

}

56

57

/**

58

* Individual validation error for a specific field

59

*/

60

class ValidationErrorItem {

61

/** Error message */

62

message: string;

63

/** Validation type */

64

type: string;

65

/** Field path */

66

path: string;

67

/** Field value that failed */

68

value: any;

69

/** Validator origin */

70

origin: string;

71

/** Model instance */

72

instance?: Model;

73

/** Validator key */

74

validatorKey?: string;

75

/** Validator name */

76

validatorName?: string;

77

/** Validator arguments */

78

validatorArgs?: any[];

79

}

80

81

/**

82

* Unique constraint violation error

83

*/

84

class UniqueConstraintError extends ValidationError {

85

/** Fields that caused the constraint violation */

86

fields: string[];

87

/** Values that caused the violation */

88

value: any;

89

/** Index name */

90

index: string;

91

/** Relation name */

92

reltype?: string;

93

}

94

95

/**

96

* Foreign key constraint violation error

97

*/

98

class ForeignKeyConstraintError extends DatabaseError {

99

/** Referenced table */

100

table: string;

101

/** Referenced fields */

102

fields: string[];

103

/** Referenced value */

104

value: any;

105

/** Constraint index */

106

index: string;

107

/** Relation type */

108

reltype?: string;

109

}

110

111

/**

112

* Exclusion constraint violation error

113

*/

114

class ExclusionConstraintError extends DatabaseError {

115

/** Constraint fields */

116

fields: string[];

117

/** Constraint table */

118

table: string;

119

/** Constraint index */

120

constraint: string;

121

}

122

```

123

124

**Usage Examples:**

125

126

```typescript

127

try {

128

await User.create({

129

email: 'invalid-email',

130

age: -5

131

});

132

} catch (error) {

133

if (error instanceof ValidationError) {

134

console.log('Validation failed:');

135

error.errors.forEach(err => {

136

console.log(`- ${err.path}: ${err.message}`);

137

});

138

139

// Check specific field errors

140

if (error.fields.email) {

141

console.log('Email validation failed');

142

}

143

}

144

}

145

146

// Handle unique constraint violations

147

try {

148

await User.create({

149

email: 'existing@example.com' // Already exists

150

});

151

} catch (error) {

152

if (error instanceof UniqueConstraintError) {

153

console.log(`Duplicate value for fields: ${error.fields.join(', ')}`);

154

console.log(`Constraint: ${error.index}`);

155

}

156

}

157

158

// Handle foreign key violations

159

try {

160

await Post.create({

161

title: 'My Post',

162

userId: 999 // Non-existent user

163

});

164

} catch (error) {

165

if (error instanceof ForeignKeyConstraintError) {

166

console.log(`Foreign key violation on table: ${error.table}`);

167

console.log(`Fields: ${error.fields.join(', ')}`);

168

}

169

}

170

```

171

172

### Connection Errors

173

174

Errors related to database connectivity and access.

175

176

```typescript { .api }

177

/**

178

* Base connection error

179

*/

180

class ConnectionError extends BaseError {

181

/** Original connection error */

182

original?: Error;

183

}

184

185

/**

186

* Database access denied

187

*/

188

class AccessDeniedError extends ConnectionError {}

189

190

/**

191

* Connection acquisition timeout

192

*/

193

class ConnectionAcquireTimeoutError extends ConnectionError {}

194

195

/**

196

* Connection refused by database

197

*/

198

class ConnectionRefusedError extends ConnectionError {}

199

200

/**

201

* Connection timed out

202

*/

203

class ConnectionTimedOutError extends ConnectionError {}

204

205

/**

206

* Database host not found

207

*/

208

class HostNotFoundError extends ConnectionError {}

209

210

/**

211

* Database host not reachable

212

*/

213

class HostNotReachableError extends ConnectionError {}

214

215

/**

216

* Invalid connection configuration

217

*/

218

class InvalidConnectionError extends ConnectionError {}

219

220

/**

221

* Database timeout error

222

*/

223

class TimeoutError extends DatabaseError {}

224

```

225

226

**Usage Examples:**

227

228

```typescript

229

try {

230

await sequelize.authenticate();

231

} catch (error) {

232

if (error instanceof ConnectionRefusedError) {

233

console.log('Database refused connection - check if database is running');

234

} else if (error instanceof AccessDeniedError) {

235

console.log('Access denied - check credentials');

236

} else if (error instanceof HostNotFoundError) {

237

console.log('Database host not found - check hostname');

238

} else if (error instanceof ConnectionTimedOutError) {

239

console.log('Connection timed out - check network or increase timeout');

240

}

241

}

242

243

// Handle query timeouts

244

try {

245

await User.findAll({

246

// Long-running query

247

});

248

} catch (error) {

249

if (error instanceof TimeoutError) {

250

console.log('Query timed out - consider optimizing or increasing timeout');

251

}

252

}

253

```

254

255

### Application Logic Errors

256

257

Errors related to application logic and ORM usage.

258

259

```typescript { .api }

260

/**

261

* Model instance-related error

262

*/

263

class InstanceError extends BaseError {}

264

265

/**

266

* Association-related error

267

*/

268

class AssociationError extends BaseError {}

269

270

/**

271

* Query-related error

272

*/

273

class QueryError extends BaseError {

274

/** SQL query */

275

sql?: string;

276

/** Query parameters */

277

parameters?: any[];

278

}

279

280

/**

281

* Scope-related error

282

*/

283

class SequelizeScopeError extends BaseError {}

284

285

/**

286

* Eager loading error

287

*/

288

class EagerLoadingError extends BaseError {}

289

290

/**

291

* Empty result error (when expecting results)

292

*/

293

class EmptyResultError extends BaseError {}

294

295

/**

296

* Optimistic locking error

297

*/

298

class OptimisticLockError extends BaseError {}

299

300

/**

301

* Bulk operation error

302

*/

303

class BulkRecordError extends BaseError {

304

/** Records that failed */

305

errors: Error[];

306

}

307

308

/**

309

* Multiple errors aggregated

310

*/

311

class AggregateError extends BaseError {

312

/** Individual errors */

313

errors: Error[];

314

}

315

```

316

317

**Usage Examples:**

318

319

```typescript

320

// Handle empty results

321

try {

322

const user = await User.findOne({

323

where: { id: 999 },

324

rejectOnEmpty: true // Throws EmptyResultError if not found

325

});

326

} catch (error) {

327

if (error instanceof EmptyResultError) {

328

console.log('User not found');

329

}

330

}

331

332

// Handle optimistic locking

333

try {

334

const user = await User.findByPk(1);

335

user.name = 'Updated';

336

await user.save(); // May fail if record was modified

337

} catch (error) {

338

if (error instanceof OptimisticLockError) {

339

console.log('Record was modified by another process');

340

// Reload and retry

341

}

342

}

343

344

// Handle bulk operation errors

345

try {

346

await User.bulkCreate([

347

{ email: 'user1@example.com' },

348

{ email: 'invalid-email' }, // Will fail validation

349

{ email: 'user3@example.com' }

350

]);

351

} catch (error) {

352

if (error instanceof BulkRecordError) {

353

console.log(`${error.errors.length} records failed`);

354

error.errors.forEach((err, index) => {

355

console.log(`Record ${index}: ${err.message}`);

356

});

357

}

358

}

359

```

360

361

### Error Handling Patterns

362

363

Common patterns for handling Sequelize errors in applications.

364

365

```typescript { .api }

366

// Error type guards

367

function isSequelizeError(error: any): error is BaseError {

368

return error instanceof BaseError;

369

}

370

371

function isValidationError(error: any): error is ValidationError {

372

return error instanceof ValidationError;

373

}

374

375

function isConnectionError(error: any): error is ConnectionError {

376

return error instanceof ConnectionError;

377

}

378

```

379

380

**Usage Examples:**

381

382

```typescript

383

// Comprehensive error handling middleware (Express.js example)

384

function sequelizeErrorHandler(error: any, req: any, res: any, next: any) {

385

if (!isSequelizeError(error)) {

386

return next(error);

387

}

388

389

// Validation errors

390

if (error instanceof ValidationError) {

391

return res.status(400).json({

392

type: 'validation_error',

393

message: 'Validation failed',

394

errors: error.errors.map(err => ({

395

field: err.path,

396

message: err.message,

397

value: err.value

398

}))

399

});

400

}

401

402

// Unique constraint violations

403

if (error instanceof UniqueConstraintError) {

404

return res.status(409).json({

405

type: 'duplicate_error',

406

message: `Duplicate value for: ${error.fields.join(', ')}`,

407

fields: error.fields

408

});

409

}

410

411

// Foreign key violations

412

if (error instanceof ForeignKeyConstraintError) {

413

return res.status(400).json({

414

type: 'reference_error',

415

message: 'Invalid reference to related record',

416

table: error.table,

417

fields: error.fields

418

});

419

}

420

421

// Connection errors

422

if (isConnectionError(error)) {

423

console.error('Database connection error:', error);

424

return res.status(503).json({

425

type: 'database_error',

426

message: 'Database temporarily unavailable'

427

});

428

}

429

430

// Other database errors

431

if (error instanceof DatabaseError) {

432

console.error('Database error:', error.sql, error.parameters);

433

return res.status(500).json({

434

type: 'database_error',

435

message: 'Internal database error'

436

});

437

}

438

439

// Generic Sequelize errors

440

return res.status(500).json({

441

type: 'sequelize_error',

442

message: error.message

443

});

444

}

445

446

// Retry pattern for connection errors

447

async function withRetry<T>(

448

operation: () => Promise<T>,

449

maxRetries: number = 3,

450

delay: number = 1000

451

): Promise<T> {

452

let lastError: Error;

453

454

for (let attempt = 1; attempt <= maxRetries; attempt++) {

455

try {

456

return await operation();

457

} catch (error) {

458

lastError = error;

459

460

// Only retry on connection errors

461

if (isConnectionError(error) && attempt < maxRetries) {

462

console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);

463

await new Promise(resolve => setTimeout(resolve, delay));

464

delay *= 2; // Exponential backoff

465

continue;

466

}

467

468

throw error;

469

}

470

}

471

472

throw lastError!;

473

}

474

475

// Usage with retry

476

const user = await withRetry(async () => {

477

return await User.findByPk(1);

478

});

479

480

// Validation helper

481

async function validateAndCreate<T extends Model>(

482

model: typeof Model,

483

data: any

484

): Promise<T> {

485

try {

486

return await model.create(data);

487

} catch (error) {

488

if (error instanceof ValidationError) {

489

// Transform validation errors for client

490

const validationErrors = error.errors.reduce((acc, err) => {

491

acc[err.path] = err.message;

492

return acc;

493

}, {} as Record<string, string>);

494

495

throw new Error(JSON.stringify({

496

type: 'validation_failed',

497

errors: validationErrors

498

}));

499

}

500

throw error;

501

}

502

}

503

```

504

505

### Custom Error Classes

506

507

Creating application-specific error classes that extend Sequelize errors.

508

509

```typescript { .api }

510

// Custom business logic errors

511

class InsufficientFundsError extends BaseError {

512

constructor(balance: number, required: number) {

513

super(`Insufficient funds: balance ${balance}, required ${required}`);

514

this.name = 'InsufficientFundsError';

515

}

516

}

517

518

class UserNotActiveError extends BaseError {

519

constructor(userId: number) {

520

super(`User ${userId} is not active`);

521

this.name = 'UserNotActiveError';

522

}

523

}

524

525

// Usage in business logic

526

async function transferFunds(fromUserId: number, toUserId: number, amount: number) {

527

return await sequelize.transaction(async (t) => {

528

const fromUser = await User.findByPk(fromUserId, { transaction: t });

529

const toUser = await User.findByPk(toUserId, { transaction: t });

530

531

if (!fromUser?.isActive) {

532

throw new UserNotActiveError(fromUserId);

533

}

534

535

if (fromUser.balance < amount) {

536

throw new InsufficientFundsError(fromUser.balance, amount);

537

}

538

539

// Perform transfer...

540

});

541

}

542

```