or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analytics-metrics.mdclient-setup.mddata.mddelivery-usage.mderror-handling.mdindex.mdjwt-signing.mdjwt.mdlive-streaming.mdplayback-control.mdsystem-operations.mdsystem.mdtranscription-vocabularies.mdupload-utilities.mdvideo-assets.mdvideo-playback.mdvideo-uploads.mdvideo.mdweb-inputs.mdwebhooks.md

error-handling.mddocs/

0

# Error Handling

1

2

Comprehensive error classes and handling patterns for different failure scenarios in the Mux Node SDK including network errors, authentication issues, and API-specific errors.

3

4

## Error Class Hierarchy

5

6

All Mux SDK errors extend from the base MuxError class, providing consistent error handling across all operations.

7

8

```typescript { .api }

9

/**

10

* Base error class for all Mux SDK errors

11

*/

12

class MuxError extends Error {

13

/** Error name identifier */

14

override readonly name: string;

15

/** Error message */

16

override readonly message: string;

17

/** Stack trace */

18

override readonly stack?: string;

19

}

20

21

/**

22

* Generic API error with HTTP details

23

*/

24

class APIError extends MuxError {

25

/** HTTP status code */

26

readonly status: number | undefined;

27

/** Response headers */

28

readonly headers: Core.Headers | undefined;

29

/** Error response body */

30

readonly error: Object | undefined;

31

}

32

```

33

34

### HTTP Status Error Classes

35

36

Specific error classes for different HTTP status codes with detailed context information.

37

38

```typescript { .api }

39

/**

40

* 400 Bad Request - Invalid request parameters

41

*/

42

class BadRequestError extends APIError {

43

override readonly status: 400;

44

}

45

46

/**

47

* 401 Unauthorized - Authentication failed

48

*/

49

class AuthenticationError extends APIError {

50

override readonly status: 401;

51

}

52

53

/**

54

* 403 Forbidden - Access denied for resource

55

*/

56

class PermissionDeniedError extends APIError {

57

override readonly status: 403;

58

}

59

60

/**

61

* 404 Not Found - Resource not found

62

*/

63

class NotFoundError extends APIError {

64

override readonly status: 404;

65

}

66

67

/**

68

* 409 Conflict - Resource conflict (duplicate creation, etc.)

69

*/

70

class ConflictError extends APIError {

71

override readonly status: 409;

72

}

73

74

/**

75

* 422 Unprocessable Entity - Validation errors

76

*/

77

class UnprocessableEntityError extends APIError {

78

override readonly status: 422;

79

}

80

81

/**

82

* 429 Too Many Requests - Rate limit exceeded

83

*/

84

class RateLimitError extends APIError {

85

override readonly status: 429;

86

/** Retry after seconds */

87

readonly retryAfter?: number;

88

}

89

90

/**

91

* 500+ Server Error - Server-side errors

92

*/

93

class InternalServerError extends APIError {

94

override readonly status: number; // 500, 502, 503, etc.

95

}

96

```

97

98

### Network and Connection Errors

99

100

Error classes for network-related failures and connection issues.

101

102

```typescript { .api }

103

/**

104

* Network connection failure

105

*/

106

class APIConnectionError extends MuxError {

107

/** Original network error */

108

readonly cause?: Error;

109

}

110

111

/**

112

* Request timeout

113

*/

114

class APIConnectionTimeoutError extends APIConnectionError {

115

/** Timeout duration in milliseconds */

116

readonly timeout?: number;

117

}

118

119

/**

120

* Request aborted by user

121

*/

122

class APIUserAbortError extends APIConnectionError {

123

/** Abort reason */

124

readonly reason?: string;

125

}

126

```

127

128

## Error Handling Patterns

129

130

### Basic Error Handling

131

132

```typescript

133

import {

134

MuxError,

135

AuthenticationError,

136

NotFoundError,

137

BadRequestError,

138

} from '@mux/mux-node';

139

140

async function handleBasicErrors() {

141

try {

142

const asset = await mux.video.assets.retrieve('asset-id');

143

console.log('Asset retrieved:', asset.id);

144

} catch (error) {

145

if (error instanceof AuthenticationError) {

146

console.error('Authentication failed - check your token credentials');

147

} else if (error instanceof NotFoundError) {

148

console.error('Asset not found');

149

} else if (error instanceof BadRequestError) {

150

console.error('Invalid request parameters');

151

} else if (error instanceof MuxError) {

152

console.error('Mux API error:', error.message);

153

} else {

154

console.error('Unexpected error:', error);

155

}

156

}

157

}

158

```

159

160

### Detailed Error Information

161

162

```typescript

163

import { APIError } from '@mux/mux-node';

164

165

async function handleDetailedErrors() {

166

try {

167

const asset = await mux.video.assets.create({

168

inputs: [{ url: 'invalid-url' }],

169

});

170

} catch (error) {

171

if (error instanceof APIError) {

172

console.error('API Error Details:');

173

console.error('Status:', error.status);

174

console.error('Message:', error.message);

175

console.error('Headers:', error.headers);

176

console.error('Error Body:', error.error);

177

178

// Access detailed error information

179

if (error.error && typeof error.error === 'object') {

180

const errorBody = error.error as any;

181

console.error('Error Code:', errorBody.code);

182

console.error('Error Details:', errorBody.details);

183

}

184

}

185

}

186

}

187

```

188

189

### Retry Logic with Error Handling

190

191

```typescript

192

import {

193

RateLimitError,

194

APIConnectionTimeoutError,

195

InternalServerError,

196

} from '@mux/mux-node';

197

198

async function withRetry<T>(

199

operation: () => Promise<T>,

200

maxRetries: number = 3

201

): Promise<T> {

202

let lastError: Error;

203

204

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

205

try {

206

return await operation();

207

} catch (error) {

208

lastError = error as Error;

209

210

// Determine if error is retryable

211

const isRetryable = error instanceof RateLimitError ||

212

error instanceof APIConnectionTimeoutError ||

213

error instanceof InternalServerError;

214

215

if (!isRetryable || attempt === maxRetries) {

216

throw error;

217

}

218

219

// Calculate delay based on error type

220

let delay = Math.pow(2, attempt - 1) * 1000; // Exponential backoff

221

222

if (error instanceof RateLimitError && error.retryAfter) {

223

delay = error.retryAfter * 1000;

224

}

225

226

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

227

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

228

}

229

}

230

231

throw lastError!;

232

}

233

234

// Usage

235

const asset = await withRetry(() =>

236

mux.video.assets.create({

237

inputs: [{ url: 'https://example.com/video.mp4' }],

238

})

239

);

240

```

241

242

### Validation Error Handling

243

244

```typescript

245

import { UnprocessableEntityError } from '@mux/mux-node';

246

247

async function handleValidationErrors() {

248

try {

249

const asset = await mux.video.assets.create({

250

inputs: [{ url: '' }], // Invalid empty URL

251

playback_policies: ['invalid-policy'], // Invalid policy

252

});

253

} catch (error) {

254

if (error instanceof UnprocessableEntityError) {

255

console.error('Validation errors occurred:');

256

257

// Parse validation errors from response body

258

const errorBody = error.error as any;

259

if (errorBody?.errors) {

260

for (const validationError of errorBody.errors) {

261

console.error(`Field: ${validationError.field}`);

262

console.error(`Message: ${validationError.message}`);

263

console.error(`Code: ${validationError.code}`);

264

}

265

}

266

}

267

}

268

}

269

```

270

271

### Upload Error Handling

272

273

```typescript

274

import { APIConnectionError, BadRequestError } from '@mux/mux-node';

275

276

async function handleUploadErrors() {

277

try {

278

const upload = await mux.video.uploads.create({

279

cors_origin: 'https://example.com',

280

});

281

282

// Monitor upload status with error handling

283

const checkUploadStatus = async (): Promise<string> => {

284

while (true) {

285

try {

286

const uploadStatus = await mux.video.uploads.retrieve(upload.id);

287

288

switch (uploadStatus.status) {

289

case 'asset_created':

290

return uploadStatus.asset_id!;

291

292

case 'errored':

293

throw new Error(`Upload failed: ${uploadStatus.error?.message}`);

294

295

case 'cancelled':

296

throw new Error('Upload was cancelled');

297

298

case 'timed_out':

299

throw new Error('Upload timed out');

300

301

case 'waiting':

302

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

303

break;

304

}

305

} catch (error) {

306

if (error instanceof APIConnectionError) {

307

console.warn('Connection error checking upload status, retrying...');

308

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

309

} else {

310

throw error;

311

}

312

}

313

}

314

};

315

316

const assetId = await checkUploadStatus();

317

console.log('Upload completed, asset created:', assetId);

318

319

} catch (error) {

320

if (error instanceof BadRequestError) {

321

console.error('Invalid upload parameters:', error.message);

322

} else {

323

console.error('Upload error:', error);

324

}

325

}

326

}

327

```

328

329

### Webhook Signature Verification Errors

330

331

```typescript

332

async function handleWebhookErrors(body: string, headers: Record<string, string>) {

333

try {

334

const event = mux.webhooks.unwrap(body, headers);

335

console.log('Webhook event:', event.type);

336

} catch (error) {

337

if (error instanceof MuxError) {

338

// Webhook signature verification failed

339

console.error('Invalid webhook signature');

340

// Return 400 status to webhook sender

341

return { status: 400, message: 'Invalid signature' };

342

} else {

343

console.error('Webhook processing error:', error);

344

// Return 500 status for processing errors

345

return { status: 500, message: 'Processing error' };

346

}

347

}

348

349

return { status: 200, message: 'OK' };

350

}

351

```

352

353

### Error Recovery Patterns

354

355

```typescript

356

import { AuthenticationError, NotFoundError } from '@mux/mux-node';

357

358

class MuxService {

359

private fallbackAssetId = 'default-asset-id';

360

361

async getAssetWithFallback(assetId: string) {

362

try {

363

return await mux.video.assets.retrieve(assetId);

364

} catch (error) {

365

if (error instanceof NotFoundError) {

366

console.warn(`Asset ${assetId} not found, using fallback`);

367

return await mux.video.assets.retrieve(this.fallbackAssetId);

368

} else if (error instanceof AuthenticationError) {

369

console.error('Authentication error - token may be expired');

370

await this.refreshAuthToken();

371

return await mux.video.assets.retrieve(assetId);

372

} else {

373

throw error;

374

}

375

}

376

}

377

378

private async refreshAuthToken() {

379

// Implement token refresh logic

380

console.log('Refreshing authentication token...');

381

}

382

}

383

```

384

385

### Error Logging and Monitoring

386

387

```typescript

388

import { APIError, APIConnectionError } from '@mux/mux-node';

389

390

function logError(error: Error, context?: Record<string, any>) {

391

const logData: Record<string, any> = {

392

timestamp: new Date().toISOString(),

393

error_type: error.constructor.name,

394

message: error.message,

395

stack: error.stack,

396

...context,

397

};

398

399

if (error instanceof APIError) {

400

logData.status = error.status;

401

logData.headers = error.headers;

402

logData.error_body = error.error;

403

}

404

405

if (error instanceof APIConnectionError) {

406

logData.network_error = true;

407

logData.cause = error.cause?.message;

408

}

409

410

// Send to logging service

411

console.error('Mux SDK Error:', JSON.stringify(logData, null, 2));

412

413

// Could also send to external monitoring service

414

// sendToMonitoring(logData);

415

}

416

417

// Usage in error handlers

418

try {

419

await mux.video.assets.create(params);

420

} catch (error) {

421

logError(error as Error, {

422

operation: 'asset_creation',

423

params: params,

424

user_id: 'user-123',

425

});

426

throw error;

427

}

428

```

429

430

## Error Prevention Best Practices

431

432

### Input Validation

433

434

```typescript

435

function validateAssetInput(input: any): string[] {

436

const errors: string[] = [];

437

438

if (!input.inputs || !Array.isArray(input.inputs) || input.inputs.length === 0) {

439

errors.push('At least one input is required');

440

}

441

442

for (const inputItem of input.inputs || []) {

443

if (!inputItem.url || typeof inputItem.url !== 'string') {

444

errors.push('Input URL is required and must be a string');

445

}

446

447

try {

448

new URL(inputItem.url);

449

} catch {

450

errors.push(`Invalid URL format: ${inputItem.url}`);

451

}

452

}

453

454

if (input.playback_policies) {

455

const validPolicies = ['public', 'signed', 'drm'];

456

for (const policy of input.playback_policies) {

457

if (!validPolicies.includes(policy)) {

458

errors.push(`Invalid playback policy: ${policy}`);

459

}

460

}

461

}

462

463

return errors;

464

}

465

466

async function createAssetSafely(input: any) {

467

const validationErrors = validateAssetInput(input);

468

if (validationErrors.length > 0) {

469

throw new Error(`Validation failed: ${validationErrors.join(', ')}`);

470

}

471

472

return await mux.video.assets.create(input);

473

}

474

```

475

476

## Types

477

478

```typescript { .api }

479

interface ErrorResponse {

480

/** Error code identifier */

481

code?: string;

482

/** Human-readable error message */

483

message: string;

484

/** Detailed error information */

485

details?: Record<string, any>;

486

/** Field-specific validation errors */

487

errors?: Array<ValidationError>;

488

}

489

490

interface ValidationError {

491

/** Field that failed validation */

492

field: string;

493

/** Validation error message */

494

message: string;

495

/** Validation error code */

496

code: string;

497

/** Invalid value */

498

rejected_value?: any;

499

}

500

501

interface RetryConfiguration {

502

/** Maximum number of retry attempts */

503

max_retries: number;

504

/** Initial delay in milliseconds */

505

initial_delay: number;

506

/** Maximum delay in milliseconds */

507

max_delay: number;

508

/** Backoff multiplier */

509

backoff_factor: number;

510

}

511

```