Core functions and utilities for Langfuse packages including API client, logging, media handling, and OpenTelemetry tracing attributes
Structured error classes for API interactions with status codes, response bodies, timeout handling, and HTTP-specific error types.
Base error class for all API-related errors with detailed context about the failed request.
class LangfuseAPIError extends Error {
readonly statusCode?: number;
readonly body?: unknown;
readonly rawResponse?: RawResponse;
constructor(params: {
message?: string;
statusCode?: number;
body?: unknown;
rawResponse?: RawResponse;
});
}
interface RawResponse {
statusCode: number;
headers: Record<string, string>;
body: unknown;
}Import:
import { LangfuseAPIError } from '@langfuse/core';Creates a new API error with context about the failed request.
constructor(params: {
message?: string;
statusCode?: number;
body?: unknown;
rawResponse?: RawResponse;
})Parameters:
message (optional) - Human-readable error messagestatusCode (optional) - HTTP status code (e.g., 400, 404, 500)body (optional) - Response body from the API (may contain error details)rawResponse (optional) - Complete raw HTTP responseProperties:
statusCode?: number - HTTP status code of the failed requestbody?: unknown - Response body (often contains error details from API)rawResponse?: RawResponse - Complete raw response with headers and bodymessage: string - Error message (inherited from Error)name: string - Error name "LangfuseAPIError" (inherited from Error)stack?: string - Stack trace (inherited from Error)Usage Examples:
import { LangfuseAPIClient, LangfuseAPIError } from '@langfuse/core';
const client = new LangfuseAPIClient({ /* ... */ });
try {
const trace = await client.trace.get('invalid-id');
} catch (error) {
if (error instanceof LangfuseAPIError) {
console.error('API Error:', error.message);
console.error('Status Code:', error.statusCode);
console.error('Response Body:', error.body);
// Access detailed error information
if (error.statusCode === 404) {
console.log('Trace not found');
} else if (error.statusCode === 429) {
console.log('Rate limited');
} else if (error.statusCode && error.statusCode >= 500) {
console.log('Server error');
}
// Log raw response for debugging
if (error.rawResponse) {
console.error('Raw Response:', {
status: error.rawResponse.statusCode,
headers: error.rawResponse.headers,
body: error.rawResponse.body
});
}
} else {
console.error('Unexpected error:', error);
}
}Error thrown when API requests exceed the configured timeout duration.
class LangfuseAPITimeoutError extends Error {
constructor(message: string);
}Import:
import { LangfuseAPITimeoutError } from '@langfuse/core';Creates a new timeout error.
constructor(message: string)Parameters:
message - Description of the timeout (includes duration and operation)Properties:
message: string - Error message describing the timeoutname: string - Error name "LangfuseAPITimeoutError" (inherited from Error)stack?: string - Stack trace (inherited from Error)Usage Examples:
import {
LangfuseAPIClient,
LangfuseAPITimeoutError,
LangfuseAPIError
} from '@langfuse/core';
const client = new LangfuseAPIClient({ /* ... */ });
try {
const trace = await client.trace.get('trace-id', {
timeoutInSeconds: 5 // 5 second timeout
});
} catch (error) {
if (error instanceof LangfuseAPITimeoutError) {
console.error('Request timed out:', error.message);
// Implement retry logic or use cached data
} else if (error instanceof LangfuseAPIError) {
console.error('API error:', error.statusCode);
} else {
console.error('Unexpected error:', error);
}
}The API exports specific error classes for common HTTP status codes, all extending LangfuseAPIError.
class Error extends LangfuseAPIError {
// Generic error (400 Bad Request)
}
class UnauthorizedError extends LangfuseAPIError {
// 401 Unauthorized - Invalid credentials
}
class AccessDeniedError extends LangfuseAPIError {
// 403 Forbidden - Insufficient permissions
}
class NotFoundError extends LangfuseAPIError {
// 404 Not Found - Resource doesn't exist
}
class MethodNotAllowedError extends LangfuseAPIError {
// 405 Method Not Allowed - HTTP method not supported
}Import:
import {
Error,
UnauthorizedError,
AccessDeniedError,
NotFoundError,
MethodNotAllowedError
} from '@langfuse/core';Note: The generic Error class name may conflict with JavaScript's built-in Error. Consider importing with an alias:
import { Error as LangfuseError } from '@langfuse/core';Usage Examples:
import {
LangfuseAPIClient,
UnauthorizedError,
AccessDeniedError,
NotFoundError
} from '@langfuse/core';
const client = new LangfuseAPIClient({ /* ... */ });
async function getTraceWithHandling(traceId: string) {
try {
return await client.trace.get(traceId);
} catch (error) {
if (error instanceof UnauthorizedError) {
console.error('Invalid API credentials');
// Refresh credentials or prompt user to login
throw new Error('Please check your API keys');
}
if (error instanceof AccessDeniedError) {
console.error('Insufficient permissions to access trace');
// Request additional permissions
throw new Error('You do not have permission to view this trace');
}
if (error instanceof NotFoundError) {
console.log('Trace not found, returning null');
return null; // Handle gracefully
}
// Rethrow other errors
throw error;
}
}import {
LangfuseAPIClient,
LangfuseAPIError,
LangfuseAPITimeoutError,
UnauthorizedError,
AccessDeniedError,
NotFoundError
} from '@langfuse/core';
async function robustAPICall<T>(
operation: () => Promise<T>,
fallback?: T
): Promise<T | undefined> {
try {
return await operation();
} catch (error) {
// Handle specific error types
if (error instanceof LangfuseAPITimeoutError) {
console.warn('Request timed out, using fallback');
return fallback;
}
if (error instanceof UnauthorizedError) {
console.error('Authentication failed');
throw new Error('Please check your API credentials');
}
if (error instanceof AccessDeniedError) {
console.error('Access denied');
throw new Error('Insufficient permissions');
}
if (error instanceof NotFoundError) {
console.log('Resource not found, using fallback');
return fallback;
}
if (error instanceof LangfuseAPIError) {
// Generic API error
console.error(`API Error [${error.statusCode}]:`, error.message);
if (error.statusCode === 429) {
console.warn('Rate limited, please retry later');
throw new Error('Rate limit exceeded');
}
if (error.statusCode && error.statusCode >= 500) {
console.error('Server error, using fallback');
return fallback;
}
console.error('Response body:', error.body);
throw error;
}
// Unknown error
console.error('Unexpected error:', error);
throw error;
}
}
// Usage
const client = new LangfuseAPIClient({ /* ... */ });
const trace = await robustAPICall(
() => client.trace.get('trace-id'),
null // Fallback value
);import {
LangfuseAPIClient,
LangfuseAPIError,
LangfuseAPITimeoutError
} from '@langfuse/core';
async function retryWithBackoff<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
initialDelay: number = 1000
): Promise<T> {
let lastError: Error | undefined;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error as Error;
// Don't retry on client errors (4xx)
if (error instanceof LangfuseAPIError) {
if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {
// Don't retry 4xx errors (except 429 rate limit)
if (error.statusCode !== 429) {
throw error;
}
}
}
// Don't retry on final attempt
if (attempt === maxRetries - 1) {
break;
}
// Calculate delay with exponential backoff
const delay = initialDelay * Math.pow(2, attempt);
console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError!;
}
// Usage
const client = new LangfuseAPIClient({ /* ... */ });
const trace = await retryWithBackoff(
() => client.trace.get('trace-id'),
5, // Max 5 attempts
1000 // Start with 1 second delay
);import {
LangfuseAPIClient,
LangfuseAPIError,
LangfuseAPITimeoutError,
getGlobalLogger
} from '@langfuse/core';
const logger = getGlobalLogger();
async function monitoredAPICall<T>(
operationName: string,
operation: () => Promise<T>
): Promise<T> {
const startTime = Date.now();
try {
logger.debug(`Starting ${operationName}`);
const result = await operation();
const duration = Date.now() - startTime;
logger.info(`${operationName} completed in ${duration}ms`);
return result;
} catch (error) {
const duration = Date.now() - startTime;
if (error instanceof LangfuseAPITimeoutError) {
logger.error(`${operationName} timed out after ${duration}ms`);
// Send to monitoring service
sendToMonitoring({
operation: operationName,
error: 'timeout',
duration
});
} else if (error instanceof LangfuseAPIError) {
logger.error(
`${operationName} failed with status ${error.statusCode}`,
error.body
);
// Send to monitoring service
sendToMonitoring({
operation: operationName,
error: 'api_error',
statusCode: error.statusCode,
duration
});
} else {
logger.error(`${operationName} failed with unexpected error`, error);
// Send to monitoring service
sendToMonitoring({
operation: operationName,
error: 'unexpected',
duration
});
}
throw error;
}
}
// Usage
const trace = await monitoredAPICall(
'fetch_trace',
() => client.trace.get('trace-id')
);import { LangfuseAPIClient, LangfuseAPIError } from '@langfuse/core';
class CircuitBreaker {
private failureCount = 0;
private lastFailureTime = 0;
private state: 'closed' | 'open' | 'half-open' = 'closed';
constructor(
private threshold: number = 5,
private timeout: number = 60000
) {}
async execute<T>(operation: () => Promise<T>): Promise<T> {
if (this.state === 'open') {
if (Date.now() - this.lastFailureTime > this.timeout) {
this.state = 'half-open';
this.failureCount = 0;
} else {
throw new Error('Circuit breaker is open');
}
}
try {
const result = await operation();
if (this.state === 'half-open') {
this.state = 'closed';
}
this.failureCount = 0;
return result;
} catch (error) {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.threshold) {
this.state = 'open';
console.error('Circuit breaker opened due to repeated failures');
}
throw error;
}
}
}
// Usage
const client = new LangfuseAPIClient({ /* ... */ });
const breaker = new CircuitBreaker(5, 60000);
async function getTraceWithCircuitBreaker(traceId: string) {
return breaker.execute(() => client.trace.get(traceId));
}import {
LangfuseAPIError,
UnauthorizedError,
AccessDeniedError,
NotFoundError,
LangfuseAPITimeoutError
} from '@langfuse/core';
function getUserFriendlyMessage(error: unknown): string {
if (error instanceof UnauthorizedError) {
return 'Your API credentials are invalid. Please check your configuration.';
}
if (error instanceof AccessDeniedError) {
return 'You do not have permission to perform this action. Please contact your administrator.';
}
if (error instanceof NotFoundError) {
return 'The requested resource was not found.';
}
if (error instanceof LangfuseAPITimeoutError) {
return 'The request took too long to complete. Please try again.';
}
if (error instanceof LangfuseAPIError) {
if (error.statusCode === 429) {
return 'Too many requests. Please wait a moment and try again.';
}
if (error.statusCode && error.statusCode >= 500) {
return 'The Langfuse service is temporarily unavailable. Please try again later.';
}
return `An API error occurred (${error.statusCode}). Please try again.`;
}
return 'An unexpected error occurred. Please try again.';
}
// Usage in UI
try {
await client.trace.get('trace-id');
} catch (error) {
const message = getUserFriendlyMessage(error);
showErrorToUser(message);
}class LangfuseAPIError extends Error {
readonly statusCode?: number;
readonly body?: unknown;
readonly rawResponse?: RawResponse;
constructor(params: {
message?: string;
statusCode?: number;
body?: unknown;
rawResponse?: RawResponse;
});
}
class LangfuseAPITimeoutError extends Error {
constructor(message: string);
}
class Error extends LangfuseAPIError {}
class UnauthorizedError extends LangfuseAPIError {}
class AccessDeniedError extends LangfuseAPIError {}
class NotFoundError extends LangfuseAPIError {}
class MethodNotAllowedError extends LangfuseAPIError {}
interface RawResponse {
statusCode: number;
headers: Record<string, string>;
body: unknown;
}LangfuseAPIErrorstatusCode and body for debuggingInstall with Tessl CLI
npx tessl i tessl/npm-langfuse--core