or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-client.mdapi-resources.mdconstants.mderrors.mdindex.mdlogger.mdmedia.mdutils.md

errors.mddocs/

0

# Error Handling

1

2

Structured error classes for API interactions with status codes, response bodies, timeout handling, and HTTP-specific error types.

3

4

## Capabilities

5

6

### LangfuseAPIError

7

8

Base error class for all API-related errors with detailed context about the failed request.

9

10

```typescript { .api }

11

class LangfuseAPIError extends Error {

12

readonly statusCode?: number;

13

readonly body?: unknown;

14

readonly rawResponse?: RawResponse;

15

16

constructor(params: {

17

message?: string;

18

statusCode?: number;

19

body?: unknown;

20

rawResponse?: RawResponse;

21

});

22

}

23

24

interface RawResponse {

25

statusCode: number;

26

headers: Record<string, string>;

27

body: unknown;

28

}

29

```

30

31

**Import:**

32

33

```typescript

34

import { LangfuseAPIError } from '@langfuse/core';

35

```

36

37

#### Constructor

38

39

Creates a new API error with context about the failed request.

40

41

```typescript { .api }

42

constructor(params: {

43

message?: string;

44

statusCode?: number;

45

body?: unknown;

46

rawResponse?: RawResponse;

47

})

48

```

49

50

**Parameters:**

51

- `message` (optional) - Human-readable error message

52

- `statusCode` (optional) - HTTP status code (e.g., 400, 404, 500)

53

- `body` (optional) - Response body from the API (may contain error details)

54

- `rawResponse` (optional) - Complete raw HTTP response

55

56

**Properties:**

57

- `statusCode?: number` - HTTP status code of the failed request

58

- `body?: unknown` - Response body (often contains error details from API)

59

- `rawResponse?: RawResponse` - Complete raw response with headers and body

60

- `message: string` - Error message (inherited from Error)

61

- `name: string` - Error name "LangfuseAPIError" (inherited from Error)

62

- `stack?: string` - Stack trace (inherited from Error)

63

64

**Usage Examples:**

65

66

```typescript

67

import { LangfuseAPIClient, LangfuseAPIError } from '@langfuse/core';

68

69

const client = new LangfuseAPIClient({ /* ... */ });

70

71

try {

72

const trace = await client.trace.get('invalid-id');

73

} catch (error) {

74

if (error instanceof LangfuseAPIError) {

75

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

76

console.error('Status Code:', error.statusCode);

77

console.error('Response Body:', error.body);

78

79

// Access detailed error information

80

if (error.statusCode === 404) {

81

console.log('Trace not found');

82

} else if (error.statusCode === 429) {

83

console.log('Rate limited');

84

} else if (error.statusCode && error.statusCode >= 500) {

85

console.log('Server error');

86

}

87

88

// Log raw response for debugging

89

if (error.rawResponse) {

90

console.error('Raw Response:', {

91

status: error.rawResponse.statusCode,

92

headers: error.rawResponse.headers,

93

body: error.rawResponse.body

94

});

95

}

96

} else {

97

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

98

}

99

}

100

```

101

102

### LangfuseAPITimeoutError

103

104

Error thrown when API requests exceed the configured timeout duration.

105

106

```typescript { .api }

107

class LangfuseAPITimeoutError extends Error {

108

constructor(message: string);

109

}

110

```

111

112

**Import:**

113

114

```typescript

115

import { LangfuseAPITimeoutError } from '@langfuse/core';

116

```

117

118

#### Constructor

119

120

Creates a new timeout error.

121

122

```typescript { .api }

123

constructor(message: string)

124

```

125

126

**Parameters:**

127

- `message` - Description of the timeout (includes duration and operation)

128

129

**Properties:**

130

- `message: string` - Error message describing the timeout

131

- `name: string` - Error name "LangfuseAPITimeoutError" (inherited from Error)

132

- `stack?: string` - Stack trace (inherited from Error)

133

134

**Usage Examples:**

135

136

```typescript

137

import {

138

LangfuseAPIClient,

139

LangfuseAPITimeoutError,

140

LangfuseAPIError

141

} from '@langfuse/core';

142

143

const client = new LangfuseAPIClient({ /* ... */ });

144

145

try {

146

const trace = await client.trace.get('trace-id', {

147

timeoutInSeconds: 5 // 5 second timeout

148

});

149

} catch (error) {

150

if (error instanceof LangfuseAPITimeoutError) {

151

console.error('Request timed out:', error.message);

152

// Implement retry logic or use cached data

153

} else if (error instanceof LangfuseAPIError) {

154

console.error('API error:', error.statusCode);

155

} else {

156

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

157

}

158

}

159

```

160

161

### HTTP-Specific Error Classes

162

163

The API exports specific error classes for common HTTP status codes, all extending `LangfuseAPIError`.

164

165

```typescript { .api }

166

class Error extends LangfuseAPIError {

167

// Generic error (400 Bad Request)

168

}

169

170

class UnauthorizedError extends LangfuseAPIError {

171

// 401 Unauthorized - Invalid credentials

172

}

173

174

class AccessDeniedError extends LangfuseAPIError {

175

// 403 Forbidden - Insufficient permissions

176

}

177

178

class NotFoundError extends LangfuseAPIError {

179

// 404 Not Found - Resource doesn't exist

180

}

181

182

class MethodNotAllowedError extends LangfuseAPIError {

183

// 405 Method Not Allowed - HTTP method not supported

184

}

185

```

186

187

**Import:**

188

189

```typescript

190

import {

191

Error,

192

UnauthorizedError,

193

AccessDeniedError,

194

NotFoundError,

195

MethodNotAllowedError

196

} from '@langfuse/core';

197

```

198

199

**Note**: The generic `Error` class name may conflict with JavaScript's built-in Error. Consider importing with an alias:

200

201

```typescript

202

import { Error as LangfuseError } from '@langfuse/core';

203

```

204

205

**Usage Examples:**

206

207

```typescript

208

import {

209

LangfuseAPIClient,

210

UnauthorizedError,

211

AccessDeniedError,

212

NotFoundError

213

} from '@langfuse/core';

214

215

const client = new LangfuseAPIClient({ /* ... */ });

216

217

async function getTraceWithHandling(traceId: string) {

218

try {

219

return await client.trace.get(traceId);

220

} catch (error) {

221

if (error instanceof UnauthorizedError) {

222

console.error('Invalid API credentials');

223

// Refresh credentials or prompt user to login

224

throw new Error('Please check your API keys');

225

}

226

227

if (error instanceof AccessDeniedError) {

228

console.error('Insufficient permissions to access trace');

229

// Request additional permissions

230

throw new Error('You do not have permission to view this trace');

231

}

232

233

if (error instanceof NotFoundError) {

234

console.log('Trace not found, returning null');

235

return null; // Handle gracefully

236

}

237

238

// Rethrow other errors

239

throw error;

240

}

241

}

242

```

243

244

## Usage Patterns

245

246

### Comprehensive Error Handling

247

248

```typescript

249

import {

250

LangfuseAPIClient,

251

LangfuseAPIError,

252

LangfuseAPITimeoutError,

253

UnauthorizedError,

254

AccessDeniedError,

255

NotFoundError

256

} from '@langfuse/core';

257

258

async function robustAPICall<T>(

259

operation: () => Promise<T>,

260

fallback?: T

261

): Promise<T | undefined> {

262

try {

263

return await operation();

264

} catch (error) {

265

// Handle specific error types

266

if (error instanceof LangfuseAPITimeoutError) {

267

console.warn('Request timed out, using fallback');

268

return fallback;

269

}

270

271

if (error instanceof UnauthorizedError) {

272

console.error('Authentication failed');

273

throw new Error('Please check your API credentials');

274

}

275

276

if (error instanceof AccessDeniedError) {

277

console.error('Access denied');

278

throw new Error('Insufficient permissions');

279

}

280

281

if (error instanceof NotFoundError) {

282

console.log('Resource not found, using fallback');

283

return fallback;

284

}

285

286

if (error instanceof LangfuseAPIError) {

287

// Generic API error

288

console.error(`API Error [${error.statusCode}]:`, error.message);

289

290

if (error.statusCode === 429) {

291

console.warn('Rate limited, please retry later');

292

throw new Error('Rate limit exceeded');

293

}

294

295

if (error.statusCode && error.statusCode >= 500) {

296

console.error('Server error, using fallback');

297

return fallback;

298

}

299

300

console.error('Response body:', error.body);

301

throw error;

302

}

303

304

// Unknown error

305

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

306

throw error;

307

}

308

}

309

310

// Usage

311

const client = new LangfuseAPIClient({ /* ... */ });

312

313

const trace = await robustAPICall(

314

() => client.trace.get('trace-id'),

315

null // Fallback value

316

);

317

```

318

319

### Retry with Exponential Backoff

320

321

```typescript

322

import {

323

LangfuseAPIClient,

324

LangfuseAPIError,

325

LangfuseAPITimeoutError

326

} from '@langfuse/core';

327

328

async function retryWithBackoff<T>(

329

operation: () => Promise<T>,

330

maxRetries: number = 3,

331

initialDelay: number = 1000

332

): Promise<T> {

333

let lastError: Error | undefined;

334

335

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

336

try {

337

return await operation();

338

} catch (error) {

339

lastError = error as Error;

340

341

// Don't retry on client errors (4xx)

342

if (error instanceof LangfuseAPIError) {

343

if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {

344

// Don't retry 4xx errors (except 429 rate limit)

345

if (error.statusCode !== 429) {

346

throw error;

347

}

348

}

349

}

350

351

// Don't retry on final attempt

352

if (attempt === maxRetries - 1) {

353

break;

354

}

355

356

// Calculate delay with exponential backoff

357

const delay = initialDelay * Math.pow(2, attempt);

358

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

359

360

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

361

}

362

}

363

364

throw lastError!;

365

}

366

367

// Usage

368

const client = new LangfuseAPIClient({ /* ... */ });

369

370

const trace = await retryWithBackoff(

371

() => client.trace.get('trace-id'),

372

5, // Max 5 attempts

373

1000 // Start with 1 second delay

374

);

375

```

376

377

### Error Logging and Monitoring

378

379

```typescript

380

import {

381

LangfuseAPIClient,

382

LangfuseAPIError,

383

LangfuseAPITimeoutError,

384

getGlobalLogger

385

} from '@langfuse/core';

386

387

const logger = getGlobalLogger();

388

389

async function monitoredAPICall<T>(

390

operationName: string,

391

operation: () => Promise<T>

392

): Promise<T> {

393

const startTime = Date.now();

394

395

try {

396

logger.debug(`Starting ${operationName}`);

397

const result = await operation();

398

const duration = Date.now() - startTime;

399

logger.info(`${operationName} completed in ${duration}ms`);

400

return result;

401

} catch (error) {

402

const duration = Date.now() - startTime;

403

404

if (error instanceof LangfuseAPITimeoutError) {

405

logger.error(`${operationName} timed out after ${duration}ms`);

406

// Send to monitoring service

407

sendToMonitoring({

408

operation: operationName,

409

error: 'timeout',

410

duration

411

});

412

} else if (error instanceof LangfuseAPIError) {

413

logger.error(

414

`${operationName} failed with status ${error.statusCode}`,

415

error.body

416

);

417

// Send to monitoring service

418

sendToMonitoring({

419

operation: operationName,

420

error: 'api_error',

421

statusCode: error.statusCode,

422

duration

423

});

424

} else {

425

logger.error(`${operationName} failed with unexpected error`, error);

426

// Send to monitoring service

427

sendToMonitoring({

428

operation: operationName,

429

error: 'unexpected',

430

duration

431

});

432

}

433

434

throw error;

435

}

436

}

437

438

// Usage

439

const trace = await monitoredAPICall(

440

'fetch_trace',

441

() => client.trace.get('trace-id')

442

);

443

```

444

445

### Circuit Breaker Pattern

446

447

```typescript

448

import { LangfuseAPIClient, LangfuseAPIError } from '@langfuse/core';

449

450

class CircuitBreaker {

451

private failureCount = 0;

452

private lastFailureTime = 0;

453

private state: 'closed' | 'open' | 'half-open' = 'closed';

454

455

constructor(

456

private threshold: number = 5,

457

private timeout: number = 60000

458

) {}

459

460

async execute<T>(operation: () => Promise<T>): Promise<T> {

461

if (this.state === 'open') {

462

if (Date.now() - this.lastFailureTime > this.timeout) {

463

this.state = 'half-open';

464

this.failureCount = 0;

465

} else {

466

throw new Error('Circuit breaker is open');

467

}

468

}

469

470

try {

471

const result = await operation();

472

473

if (this.state === 'half-open') {

474

this.state = 'closed';

475

}

476

477

this.failureCount = 0;

478

return result;

479

} catch (error) {

480

this.failureCount++;

481

this.lastFailureTime = Date.now();

482

483

if (this.failureCount >= this.threshold) {

484

this.state = 'open';

485

console.error('Circuit breaker opened due to repeated failures');

486

}

487

488

throw error;

489

}

490

}

491

}

492

493

// Usage

494

const client = new LangfuseAPIClient({ /* ... */ });

495

const breaker = new CircuitBreaker(5, 60000);

496

497

async function getTraceWithCircuitBreaker(traceId: string) {

498

return breaker.execute(() => client.trace.get(traceId));

499

}

500

```

501

502

### User-Friendly Error Messages

503

504

```typescript

505

import {

506

LangfuseAPIError,

507

UnauthorizedError,

508

AccessDeniedError,

509

NotFoundError,

510

LangfuseAPITimeoutError

511

} from '@langfuse/core';

512

513

function getUserFriendlyMessage(error: unknown): string {

514

if (error instanceof UnauthorizedError) {

515

return 'Your API credentials are invalid. Please check your configuration.';

516

}

517

518

if (error instanceof AccessDeniedError) {

519

return 'You do not have permission to perform this action. Please contact your administrator.';

520

}

521

522

if (error instanceof NotFoundError) {

523

return 'The requested resource was not found.';

524

}

525

526

if (error instanceof LangfuseAPITimeoutError) {

527

return 'The request took too long to complete. Please try again.';

528

}

529

530

if (error instanceof LangfuseAPIError) {

531

if (error.statusCode === 429) {

532

return 'Too many requests. Please wait a moment and try again.';

533

}

534

535

if (error.statusCode && error.statusCode >= 500) {

536

return 'The Langfuse service is temporarily unavailable. Please try again later.';

537

}

538

539

return `An API error occurred (${error.statusCode}). Please try again.`;

540

}

541

542

return 'An unexpected error occurred. Please try again.';

543

}

544

545

// Usage in UI

546

try {

547

await client.trace.get('trace-id');

548

} catch (error) {

549

const message = getUserFriendlyMessage(error);

550

showErrorToUser(message);

551

}

552

```

553

554

## Type Definitions

555

556

```typescript { .api }

557

class LangfuseAPIError extends Error {

558

readonly statusCode?: number;

559

readonly body?: unknown;

560

readonly rawResponse?: RawResponse;

561

562

constructor(params: {

563

message?: string;

564

statusCode?: number;

565

body?: unknown;

566

rawResponse?: RawResponse;

567

});

568

}

569

570

class LangfuseAPITimeoutError extends Error {

571

constructor(message: string);

572

}

573

574

class Error extends LangfuseAPIError {}

575

class UnauthorizedError extends LangfuseAPIError {}

576

class AccessDeniedError extends LangfuseAPIError {}

577

class NotFoundError extends LangfuseAPIError {}

578

class MethodNotAllowedError extends LangfuseAPIError {}

579

580

interface RawResponse {

581

statusCode: number;

582

headers: Record<string, string>;

583

body: unknown;

584

}

585

```

586

587

## Best Practices

588

589

1. **Specific Error Handling**: Always check for specific error types before handling generic `LangfuseAPIError`

590

2. **Timeout Configuration**: Set appropriate timeouts based on operation type (longer for batch operations)

591

3. **Retry Logic**: Implement exponential backoff for transient errors (timeouts, 5xx, 429)

592

4. **Don't Retry 4xx**: Never retry client errors (4xx) except for 429 rate limiting

593

5. **Log Error Details**: Always log `statusCode` and `body` for debugging

594

6. **User-Friendly Messages**: Transform technical errors into user-friendly messages in UI

595

7. **Circuit Breaker**: Use circuit breaker pattern for external service calls

596

8. **Monitoring**: Send error metrics to monitoring services for alerting

597

9. **Graceful Degradation**: Provide fallback values or cached data when possible

598

10. **Error Context**: Include operation context in error logs (operation name, parameters, duration)

599

600

## Common HTTP Status Codes

601

602

- **400 Bad Request**: Invalid request parameters or body

603

- **401 Unauthorized**: Missing or invalid API credentials

604

- **403 Forbidden**: Valid credentials but insufficient permissions

605

- **404 Not Found**: Resource doesn't exist

606

- **405 Method Not Allowed**: HTTP method not supported for endpoint

607

- **429 Too Many Requests**: Rate limit exceeded (implement backoff and retry)

608

- **500 Internal Server Error**: Server-side error (safe to retry)

609

- **502 Bad Gateway**: Upstream service error (safe to retry)

610

- **503 Service Unavailable**: Service temporarily down (safe to retry)

611

- **504 Gateway Timeout**: Upstream service timeout (safe to retry)

612