Error Handling in v1 API
@meeting-baas/sdk - v1 API Reference / v1-error-handling
Error Handling in v1 API
The v1 API uses a discriminated union response type that makes error handling type-safe and straightforward.
Response Structure
type ApiResponse\<T\> =
| { success: true; data: T; error?: never }
| { success: false; error: ZodError | Error; data?: never }Error Types
Validation Errors (ZodError)
Parameter validation failures return a ZodError:
import { ZodError } from "zod";
const result = await client.joinMeeting({
meeting_url: "not-a-valid-url",
bot_name: "Test Bot",
reserved: false
});
if (!result.success) {
if (result.error instanceof ZodError) {
console.error("Validation failed:");
result.error.errors.forEach(err => {
console.error(` Field: ${err.path.join(".")}`);
console.error(` Error: ${err.message}`);
console.error(` Received: ${err.code}`);
});
}
}API Errors (Error)
API-level errors return a standard Error object:
const result = await client.joinMeeting({
meeting_url: "https://meet.google.com/abc-def-ghi",
bot_name: "Test Bot",
reserved: false
});
if (!result.success && !(result.error instanceof ZodError)) {
console.error("API error:", result.error.message);
// Parse error details if available
try {
const errorData = JSON.parse(result.error.message);
console.error("Status:", errorData.status);
console.error("Details:", errorData.data);
} catch {
// Not JSON, just a regular error message
}
}Common Error Scenarios
Invalid Meeting URL
const result = await client.joinMeeting({
meeting_url: "https://invalid-platform.com/meeting",
bot_name: "Test Bot",
reserved: false
});
if (!result.success) {
if (result.error instanceof ZodError) {
const urlError = result.error.errors.find(
err => err.path.includes("meeting_url")
);
if (urlError) {
console.error("Invalid meeting URL format");
}
} else {
console.error("Meeting URL not supported");
}
}Authentication Errors
const client = createBaasClient({
api_key: "invalid-key"
});
const result = await client.joinMeeting({ ... });
if (!result.success) {
if (result.error.message.includes("401") ||
result.error.message.includes("Unauthorized")) {
console.error("Invalid API key. Please check your credentials.");
}
}Rate Limiting
const result = await client.joinMeeting({ ... });
if (!result.success) {
if (result.error.message.includes("429") ||
result.error.message.includes("rate limit")) {
console.error("Rate limit exceeded. Please retry after some time.");
// Implement exponential backoff
await new Promise(resolve => setTimeout(resolve, 5000));
// Retry...
}
}Not Found Errors
const result = await client.getMeetingData({
bot_id: "non-existent-id"
});
if (!result.success) {
if (result.error.message.includes("404") ||
result.error.message.includes("not found")) {
console.error("Bot not found. It may have been deleted.");
}
}Error Handling Patterns
Basic Pattern
async function safeBotOperation\<T\>(
operation: () => Promise<{ success: boolean; data?: T; error?: any }>
): Promise<T | null> {
const result = await operation();
if (result.success) {
return result.data;
}
console.error("Operation failed:", result.error);
return null;
}
// Usage
const botData = await safeBotOperation(() =>
client.getMeetingData({ bot_id: "bot-123" })
);
if (botData) {
console.log("Bot status:", botData.status_changes);
}Retry Pattern
async function withRetry\<T\>(
operation: () => Promise<{ success: boolean; data?: T; error?: any }>,
maxRetries = 3
): Promise\<T\> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const result = await operation();
if (result.success) {
return result.data!;
}
const isLastAttempt = attempt === maxRetries;
const shouldRetry = !(result.error instanceof ZodError) &&
(result.error.message.includes("429") ||
result.error.message.includes("5"));
if (!shouldRetry || isLastAttempt) {
throw result.error;
}
const delay = Math.pow(2, attempt) * 1000;
console.log(`Retry ${attempt}/${maxRetries} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error("Max retries exceeded");
}
// Usage
try {
const result = await withRetry(() =>
client.joinMeeting({
meeting_url: "https://meet.google.com/abc",
bot_name: "Test Bot",
reserved: false
})
);
console.log("Bot ID:", result.bot_id);
} catch (error) {
console.error("Failed after retries:", error);
}Type-Safe Error Handling
function handleError(error: ZodError | Error): { type: string; message: string } {
if (error instanceof ZodError) {
return {
type: "validation",
message: error.errors.map(e => `${e.path.join(".")}: ${e.message}`).join(", ")
};
}
// Parse API errors
if (error.message.includes("401")) {
return { type: "auth", message: "Authentication failed" };
}
if (error.message.includes("429")) {
return { type: "rate_limit", message: "Too many requests" };
}
if (error.message.includes("404")) {
return { type: "not_found", message: "Resource not found" };
}
return { type: "unknown", message: error.message };
}
// Usage
const result = await client.joinMeeting({ ... });
if (!result.success) {
const errorInfo = handleError(result.error);
switch (errorInfo.type) {
case "validation":
console.error("Invalid parameters:", errorInfo.message);
break;
case "auth":
console.error("Authentication error:", errorInfo.message);
// Refresh credentials
break;
case "rate_limit":
console.error("Rate limited:", errorInfo.message);
// Implement backoff
break;
default:
console.error("Error:", errorInfo.message);
}
}Logging Best Practices
Development Logging
function logError(operation: string, error: ZodError | Error) {
console.error(`[${operation}] Error occurred`);
if (error instanceof ZodError) {
console.error("Validation errors:");
error.errors.forEach(err => {
console.error(` - ${err.path.join(".")}: ${err.message}`);
});
} else {
console.error("Message:", error.message);
console.error("Stack:", error.stack);
}
}
// Usage
const result = await client.joinMeeting({ ... });
if (!result.success) {
logError("joinMeeting", result.error);
}Production Logging
interface ErrorLog {
timestamp: string;
operation: string;
errorType: "validation" | "api";
message: string;
details?: any;
}
function logErrorToMonitoring(log: ErrorLog) {
// Send to your monitoring service
console.error(JSON.stringify(log));
}
const result = await client.joinMeeting({ ... });
if (!result.success) {
logErrorToMonitoring({
timestamp: new Date().toISOString(),
operation: "joinMeeting",
errorType: result.error instanceof ZodError ? "validation" : "api",
message: result.error.message,
details: result.error instanceof ZodError ? result.error.errors : undefined
});
}User-Friendly Error Messages
function getUserMessage(error: ZodError | Error): string {
if (error instanceof ZodError) {
const field = error.errors[0]?.path.join(".") || "input";
return `Invalid ${field}. Please check your input and try again.`;
}
if (error.message.includes("401")) {
return "Authentication failed. Please check your API key.";
}
if (error.message.includes("429")) {
return "Too many requests. Please try again in a few moments.";
}
if (error.message.includes("404")) {
return "The requested resource was not found.";
}
if (error.message.includes("5")) {
return "Server error. Please try again later.";
}
return "An unexpected error occurred. Please try again.";
}
// Usage in UI
const result = await client.joinMeeting({ ... });
if (!result.success) {
alert(getUserMessage(result.error));
}Complete Error Handling Example
import { createBaasClient } from "@meeting-baas/sdk";
import { ZodError } from "zod";
const client = createBaasClient({
api_key: process.env.MEETING_BAAS_API_KEY!
});
async function joinMeetingSafely(meetingUrl: string, botName: string) {
try {
const result = await client.joinMeeting({
meeting_url: meetingUrl,
bot_name: botName,
reserved: true
});
if (result.success) {
return {
ok: true,
botId: result.data.bot_id,
message: "Bot joined successfully"
};
}
// Handle validation errors
if (result.error instanceof ZodError) {
const errors = result.error.errors.map(e =>
`${e.path.join(".")}: ${e.message}`
);
return {
ok: false,
reason: "validation_error",
message: "Invalid parameters",
details: errors
};
}
// Handle API errors
const errorMessage = result.error.message;
if (errorMessage.includes("401")) {
return {
ok: false,
reason: "auth_error",
message: "Invalid API key"
};
}
if (errorMessage.includes("429")) {
return {
ok: false,
reason: "rate_limit",
message: "Rate limit exceeded"
};
}
return {
ok: false,
reason: "api_error",
message: errorMessage
};
} catch (error) {
// Network errors, timeouts, etc.
console.error("Unexpected error:", error);
return {
ok: false,
reason: "network_error",
message: "Failed to connect to Meeting BaaS API"
};
}
}
// Usage
const result = await joinMeetingSafely(
"https://meet.google.com/abc-def-ghi",
"My Bot"
);
if (result.ok) {
console.log("Success:", result.message);
console.log("Bot ID:", result.botId);
} else {
console.error("Failed:", result.message);
if (result.reason === "validation_error") {
console.error("Validation errors:", result.details);
}
}