or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-api.mderrors.mdindex.mdmultipart-uploads.mdserver-api.md

errors.mddocs/

0

# Error Handling

1

2

Comprehensive error system with specific error types for different failure scenarios and detailed error messages.

3

4

## Overview

5

6

The Vercel Blob library provides a comprehensive error handling system with specific error classes for different types of failures. All errors extend from the base `BlobError` class and include detailed error messages to help developers understand and handle various failure scenarios.

7

8

## Error Hierarchy

9

10

All blob-related errors inherit from the base `BlobError` class, which extends the standard JavaScript `Error`.

11

12

```typescript { .api }

13

class BlobError extends Error {

14

constructor(message: string);

15

}

16

```

17

18

## Error Types

19

20

### Access and Authentication Errors

21

22

#### BlobAccessError

23

24

Thrown when the request lacks proper authentication or authorization.

25

26

```typescript { .api }

27

/**

28

* Thrown when access is denied due to authentication or authorization issues

29

*/

30

class BlobAccessError extends BlobError {

31

constructor();

32

}

33

```

34

35

**Common Causes:**

36

- Invalid or missing `BLOB_READ_WRITE_TOKEN`

37

- Expired authentication token

38

- Insufficient permissions for the requested operation

39

- Invalid client token

40

41

**Example:**

42

43

```typescript

44

import { put, BlobAccessError } from '@vercel/blob';

45

46

try {

47

await put('test.txt', 'content', {

48

access: 'public',

49

token: 'invalid-token',

50

});

51

} catch (error) {

52

if (error instanceof BlobAccessError) {

53

console.error('Access denied:', error.message);

54

// Handle authentication error

55

}

56

}

57

```

58

59

### Resource Errors

60

61

#### BlobNotFoundError

62

63

Thrown when attempting to access a blob that doesn't exist.

64

65

```typescript { .api }

66

/**

67

* Thrown when a requested blob cannot be found

68

*/

69

class BlobNotFoundError extends BlobError {

70

constructor();

71

}

72

```

73

74

**Common Operations:**

75

- `head()` on non-existent blob

76

- `del()` on non-existent blob

77

- `copy()` from non-existent source

78

79

**Example:**

80

81

```typescript

82

import { head, BlobNotFoundError } from '@vercel/blob';

83

84

try {

85

const metadata = await head('non-existent-file.txt');

86

} catch (error) {

87

if (error instanceof BlobNotFoundError) {

88

console.log('File does not exist');

89

// Handle missing file

90

}

91

}

92

```

93

94

#### BlobStoreNotFoundError

95

96

Thrown when the blob store itself cannot be found.

97

98

```typescript { .api }

99

/**

100

* Thrown when the blob store cannot be found

101

*/

102

class BlobStoreNotFoundError extends BlobError {

103

constructor();

104

}

105

```

106

107

**Common Causes:**

108

- Incorrect store configuration

109

- Store has been deleted

110

- Invalid store identifier in token

111

112

#### BlobStoreSuspendedError

113

114

Thrown when operations are attempted on a suspended blob store.

115

116

```typescript { .api }

117

/**

118

* Thrown when attempting operations on a suspended blob store

119

*/

120

class BlobStoreSuspendedError extends BlobError {

121

constructor();

122

}

123

```

124

125

**Common Causes:**

126

- Account billing issues

127

- Terms of service violations

128

- Administrative suspension

129

130

### Content and Validation Errors

131

132

#### BlobContentTypeNotAllowedError

133

134

Thrown when uploading content with a disallowed MIME type.

135

136

```typescript { .api }

137

/**

138

* Thrown when the content type is not allowed for upload

139

*/

140

class BlobContentTypeNotAllowedError extends BlobError {

141

constructor(message: string);

142

}

143

```

144

145

**Common Causes:**

146

- Uploading executable files

147

- Restricted file types based on store configuration

148

- Invalid or missing content type

149

150

**Example:**

151

152

```typescript

153

import { put, BlobContentTypeNotAllowedError } from '@vercel/blob';

154

155

try {

156

await put('script.exe', executableData, {

157

access: 'public',

158

contentType: 'application/x-executable',

159

});

160

} catch (error) {

161

if (error instanceof BlobContentTypeNotAllowedError) {

162

console.error('File type not allowed:', error.message);

163

// Handle content type restriction

164

}

165

}

166

```

167

168

#### BlobPathnameMismatchError

169

170

Thrown when there's a mismatch between expected and actual pathname.

171

172

```typescript { .api }

173

/**

174

* Thrown when pathname doesn't match expected format or constraints

175

*/

176

class BlobPathnameMismatchError extends BlobError {

177

constructor(message: string);

178

}

179

```

180

181

**Common Causes:**

182

- Pathname too long (exceeds `MAXIMUM_PATHNAME_LENGTH`)

183

- Invalid characters in pathname

184

- Pathname format violations

185

186

#### BlobFileTooLargeError

187

188

Thrown when uploading files that exceed size limits.

189

190

```typescript { .api }

191

/**

192

* Thrown when file size exceeds the allowed limit

193

*/

194

class BlobFileTooLargeError extends BlobError {

195

constructor(message: string);

196

}

197

```

198

199

**Common Causes:**

200

- Single file exceeds server upload limit (4.5MB on Vercel)

201

- Multipart part smaller than minimum size (5MB, except last part)

202

- Total file size exceeds maximum (5TB)

203

204

### Service and Network Errors

205

206

#### BlobServiceNotAvailable

207

208

Thrown when the blob service is temporarily unavailable.

209

210

```typescript { .api }

211

/**

212

* Thrown when the blob service is temporarily unavailable

213

*/

214

class BlobServiceNotAvailable extends BlobError {

215

constructor();

216

}

217

```

218

219

**Common Causes:**

220

- Service maintenance

221

- Temporary outages

222

- Network connectivity issues

223

224

**Handling:**

225

226

```typescript

227

import { put, BlobServiceNotAvailable } from '@vercel/blob';

228

229

async function uploadWithRetry(pathname: string, body: any, maxRetries = 3) {

230

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

231

try {

232

return await put(pathname, body, { access: 'public' });

233

} catch (error) {

234

if (error instanceof BlobServiceNotAvailable && attempt < maxRetries) {

235

console.log(`Service unavailable, retrying... (${attempt}/${maxRetries})`);

236

await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));

237

continue;

238

}

239

throw error;

240

}

241

}

242

}

243

```

244

245

#### BlobServiceRateLimited

246

247

Thrown when requests exceed the rate limit.

248

249

```typescript { .api }

250

/**

251

* Thrown when requests exceed the allowed rate limit

252

*/

253

class BlobServiceRateLimited extends BlobError {

254

public readonly retryAfter: number;

255

constructor(seconds?: number);

256

}

257

```

258

259

**Handling:**

260

261

```typescript

262

import { put, BlobServiceRateLimited } from '@vercel/blob';

263

264

async function uploadWithRateLimit(pathname: string, body: any) {

265

try {

266

return await put(pathname, body, { access: 'public' });

267

} catch (error) {

268

if (error instanceof BlobServiceRateLimited) {

269

console.log('Rate limited, waiting before retry...');

270

await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds

271

return put(pathname, body, { access: 'public' });

272

}

273

throw error;

274

}

275

}

276

```

277

278

### Request and Token Errors

279

280

#### BlobRequestAbortedError

281

282

Thrown when a request is aborted using an AbortSignal.

283

284

```typescript { .api }

285

/**

286

* Thrown when a request is aborted via AbortSignal

287

*/

288

class BlobRequestAbortedError extends BlobError {

289

constructor();

290

}

291

```

292

293

**Example:**

294

295

```typescript

296

import { put, BlobRequestAbortedError } from '@vercel/blob';

297

298

const controller = new AbortController();

299

300

// Cancel upload after 5 seconds

301

setTimeout(() => controller.abort(), 5000);

302

303

try {

304

await put('large-file.bin', largeData, {

305

access: 'public',

306

abortSignal: controller.signal,

307

});

308

} catch (error) {

309

if (error instanceof BlobRequestAbortedError) {

310

console.log('Upload was cancelled');

311

}

312

}

313

```

314

315

#### BlobClientTokenExpiredError

316

317

Thrown when a client token has expired.

318

319

```typescript { .api }

320

/**

321

* Thrown when a client token has expired

322

*/

323

class BlobClientTokenExpiredError extends BlobError {

324

constructor();

325

}

326

```

327

328

**Handling:**

329

330

```typescript

331

import { upload, BlobClientTokenExpiredError } from '@vercel/blob/client';

332

333

async function uploadWithTokenRefresh(pathname: string, body: any) {

334

try {

335

return await upload(pathname, body, {

336

access: 'public',

337

handleUploadUrl: '/api/upload',

338

});

339

} catch (error) {

340

if (error instanceof BlobClientTokenExpiredError) {

341

console.log('Token expired, will request new token automatically');

342

// The upload function will automatically retry with a new token

343

return upload(pathname, body, {

344

access: 'public',

345

handleUploadUrl: '/api/upload',

346

});

347

}

348

throw error;

349

}

350

}

351

```

352

353

### Generic Errors

354

355

#### BlobUnknownError

356

357

Thrown for unexpected or unhandled error conditions.

358

359

```typescript { .api }

360

/**

361

* Thrown for unknown or unexpected error conditions

362

*/

363

class BlobUnknownError extends BlobError {

364

constructor();

365

}

366

```

367

368

## Error Handling Patterns

369

370

### Basic Error Handling

371

372

```typescript

373

import {

374

put,

375

BlobError,

376

BlobAccessError,

377

BlobNotFoundError,

378

BlobFileTooLargeError

379

} from '@vercel/blob';

380

381

async function handleBlobOperation() {

382

try {

383

const result = await put('test.txt', 'content', {

384

access: 'public',

385

});

386

return result;

387

388

} catch (error) {

389

if (error instanceof BlobAccessError) {

390

console.error('Authentication failed:', error.message);

391

// Redirect to login or refresh token

392

393

} else if (error instanceof BlobFileTooLargeError) {

394

console.error('File too large:', error.message);

395

// Suggest using multipart upload

396

397

} else if (error instanceof BlobError) {

398

console.error('Blob operation failed:', error.message);

399

// Generic blob error handling

400

401

} else {

402

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

403

// Handle non-blob errors

404

}

405

406

throw error; // Re-throw if needed

407

}

408

}

409

```

410

411

### Comprehensive Error Handler

412

413

```typescript

414

import {

415

BlobError,

416

BlobAccessError,

417

BlobNotFoundError,

418

BlobStoreNotFoundError,

419

BlobStoreSuspendedError,

420

BlobContentTypeNotAllowedError,

421

BlobPathnameMismatchError,

422

BlobFileTooLargeError,

423

BlobServiceNotAvailable,

424

BlobServiceRateLimited,

425

BlobRequestAbortedError,

426

BlobClientTokenExpiredError,

427

BlobUnknownError

428

} from '@vercel/blob';

429

430

interface ErrorInfo {

431

type: string;

432

message: string;

433

isRetryable: boolean;

434

suggestedAction: string;

435

}

436

437

function analyzeBlobError(error: unknown): ErrorInfo {

438

if (!(error instanceof BlobError)) {

439

return {

440

type: 'UnknownError',

441

message: String(error),

442

isRetryable: false,

443

suggestedAction: 'Check the error details and try again',

444

};

445

}

446

447

if (error instanceof BlobAccessError) {

448

return {

449

type: 'AccessError',

450

message: error.message,

451

isRetryable: false,

452

suggestedAction: 'Check authentication tokens and permissions',

453

};

454

}

455

456

if (error instanceof BlobNotFoundError) {

457

return {

458

type: 'NotFoundError',

459

message: error.message,

460

isRetryable: false,

461

suggestedAction: 'Verify the blob pathname or URL is correct',

462

};

463

}

464

465

if (error instanceof BlobStoreNotFoundError) {

466

return {

467

type: 'StoreNotFoundError',

468

message: error.message,

469

isRetryable: false,

470

suggestedAction: 'Check blob store configuration',

471

};

472

}

473

474

if (error instanceof BlobStoreSuspendedError) {

475

return {

476

type: 'StoreSuspendedError',

477

message: error.message,

478

isRetryable: false,

479

suggestedAction: 'Contact support to resolve account issues',

480

};

481

}

482

483

if (error instanceof BlobContentTypeNotAllowedError) {

484

return {

485

type: 'ContentTypeError',

486

message: error.message,

487

isRetryable: false,

488

suggestedAction: 'Use an allowed content type or modify store settings',

489

};

490

}

491

492

if (error instanceof BlobPathnameMismatchError) {

493

return {

494

type: 'PathnameError',

495

message: error.message,

496

isRetryable: false,

497

suggestedAction: 'Use a valid pathname format',

498

};

499

}

500

501

if (error instanceof BlobFileTooLargeError) {

502

return {

503

type: 'FileTooLargeError',

504

message: error.message,

505

isRetryable: false,

506

suggestedAction: 'Use multipart upload for large files',

507

};

508

}

509

510

if (error instanceof BlobServiceNotAvailable) {

511

return {

512

type: 'ServiceUnavailableError',

513

message: error.message,

514

isRetryable: true,

515

suggestedAction: 'Retry the operation after a delay',

516

};

517

}

518

519

if (error instanceof BlobServiceRateLimited) {

520

return {

521

type: 'RateLimitedError',

522

message: error.message,

523

isRetryable: true,

524

suggestedAction: 'Wait before retrying to respect rate limits',

525

};

526

}

527

528

if (error instanceof BlobRequestAbortedError) {

529

return {

530

type: 'RequestAbortedError',

531

message: error.message,

532

isRetryable: false,

533

suggestedAction: 'Restart the operation if needed',

534

};

535

}

536

537

if (error instanceof BlobClientTokenExpiredError) {

538

return {

539

type: 'TokenExpiredError',

540

message: error.message,

541

isRetryable: true,

542

suggestedAction: 'The operation will automatically retry with a new token',

543

};

544

}

545

546

if (error instanceof BlobUnknownError) {

547

return {

548

type: 'UnknownBlobError',

549

message: error.message,

550

isRetryable: false,

551

suggestedAction: 'Check the error details and contact support if needed',

552

};

553

}

554

555

return {

556

type: 'GenericBlobError',

557

message: error.message,

558

isRetryable: false,

559

suggestedAction: 'Review the error and try again',

560

};

561

}

562

563

// Usage example

564

async function robustBlobOperation() {

565

try {

566

return await put('test.txt', 'content', { access: 'public' });

567

} catch (error) {

568

const errorInfo = analyzeBlobError(error);

569

570

console.error(`${errorInfo.type}: ${errorInfo.message}`);

571

console.log(`Suggested action: ${errorInfo.suggestedAction}`);

572

573

if (errorInfo.isRetryable) {

574

console.log('This error is retryable');

575

// Implement retry logic

576

}

577

578

throw error;

579

}

580

}

581

```

582

583

### Retry with Exponential Backoff

584

585

```typescript

586

import {

587

BlobError,

588

BlobServiceNotAvailable,

589

BlobServiceRateLimited

590

} from '@vercel/blob';

591

592

async function withRetry<T>(

593

operation: () => Promise<T>,

594

maxRetries = 3,

595

baseDelay = 1000

596

): Promise<T> {

597

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

598

try {

599

return await operation();

600

} catch (error) {

601

const isRetryable =

602

error instanceof BlobServiceNotAvailable ||

603

error instanceof BlobServiceRateLimited;

604

605

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

606

throw error;

607

}

608

609

const delay = baseDelay * Math.pow(2, attempt - 1);

610

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

611

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

612

}

613

}

614

615

throw new Error('Max retries exceeded');

616

}

617

618

// Usage

619

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

620

return put('test.txt', 'content', { access: 'public' });

621

});

622

```

623

624

### Error Boundaries for React

625

626

```typescript

627

import React from 'react';

628

import { BlobError } from '@vercel/blob';

629

630

interface Props {

631

children: React.ReactNode;

632

}

633

634

interface State {

635

hasError: boolean;

636

error?: Error;

637

}

638

639

class BlobErrorBoundary extends React.Component<Props, State> {

640

constructor(props: Props) {

641

super(props);

642

this.state = { hasError: false };

643

}

644

645

static getDerivedStateFromError(error: Error): State {

646

return { hasError: true, error };

647

}

648

649

componentDidCatch(error: Error) {

650

if (error instanceof BlobError) {

651

console.error('Blob operation failed:', error.message);

652

// Log to error reporting service

653

}

654

}

655

656

render() {

657

if (this.state.hasError) {

658

return (

659

<div className="error-boundary">

660

<h2>Upload Failed</h2>

661

<p>

662

{this.state.error instanceof BlobError

663

? 'There was an issue with the file upload. Please try again.'

664

: 'An unexpected error occurred.'}

665

</p>

666

<button onClick={() => this.setState({ hasError: false })}>

667

Try Again

668

</button>

669

</div>

670

);

671

}

672

673

return this.props.children;

674

}

675

}

676

```

677

678

## Constants

679

680

### Maximum Limits

681

682

```typescript { .api }

683

const MAXIMUM_PATHNAME_LENGTH = 950; // Maximum allowed pathname length

684

```

685

686

## Best Practices

687

688

### Error Logging

689

690

```typescript

691

import { BlobError } from '@vercel/blob';

692

693

function logBlobError(error: unknown, operation: string, context?: any) {

694

if (error instanceof BlobError) {

695

console.error('Blob Error:', {

696

operation,

697

type: error.constructor.name,

698

message: error.message,

699

context,

700

timestamp: new Date().toISOString(),

701

});

702

} else {

703

console.error('Non-Blob Error:', {

704

operation,

705

error: String(error),

706

context,

707

timestamp: new Date().toISOString(),

708

});

709

}

710

}

711

```

712

713

### Graceful Degradation

714

715

```typescript

716

import { put, BlobError } from '@vercel/blob';

717

718

async function uploadWithFallback(pathname: string, content: any) {

719

try {

720

return await put(pathname, content, { access: 'public' });

721

} catch (error) {

722

if (error instanceof BlobError) {

723

console.warn('Blob upload failed, falling back to local storage');

724

// Implement fallback logic

725

return { url: `local://fallback/${pathname}` };

726

}

727

throw error;

728

}

729

}

730

```