Error Handling
AI-friendly error handling architecture requires @lovrabet/sdk v1.2.5 or later.
The Lovrabet SDK adopts an AI-friendly error handling architecture, specifically designed for Vibe Coding (AI-assisted programming) scenarios. When you use the SDK in AI programming tools like Cursor, Claude Code, or Copilot, error messages can be directly understood by AI, which automatically provides fix suggestions.
Design Philosophy
Why AI-Friendly Errors?
Traditional error handling only focuses on human developers:
// Traditional error - difficult for AI to understand context
Error: "project_id column cannot be empty"
In Vibe Coding scenarios, AI needs more context to help you fix issues:
- What type of error is this? Parameter error? Permission issue?
- Which specific field has the problem?
- How should it be fixed? Any suggestions?
- How to get the correct field information?
Lovrabet SDK's AI-friendly architecture is designed to solve these problems.
Architecture Goals
- Errors understandable by AI - Structured error messages including error type, cause, and status code
- Provide fix suggestions - Specific fix directions for different error types
- Guide AI to use tools - When more information is needed, guide AI to call MCP tools to obtain it
- Support auto-fix - AI can automatically modify code based on suggestions
LovrabetError Type
All SDK errors are thrown using the unified LovrabetError type:
import { LovrabetError } from "@lovrabet/sdk";
try {
await client.models.users.create({ name: "Zhang San" });
} catch (error) {
if (error instanceof LovrabetError) {
console.log(error.message); // Error message
console.log(error.code); // Error code
console.log(error.status); // HTTP status code
console.log(error.description); // AI-friendly detailed description
console.log(error.response); // Original server response
console.log(error.cause); // Original error (v1.2.10+)
}
}
Error Properties Reference
| Property | Type | Purpose | How AI Uses It |
|---|---|---|---|
message | string | Brief error message | Quickly understand the problem |
code | string | Error code | Determine error category |
status | number | HTTP status code | Determine if it's a client or server issue |
description | string | AI-friendly detailed description | Understand error cause, get fix suggestions |
response | object | Original response | Get more details when needed |
cause | unknown | Original error object (v1.2.10+) | Trace error source |
AI-Friendly description Field
description is the core field designed specifically for AI by the SDK (v1.2.5+), which includes:
- Error cause - What error the server returned
- Error classification - What type of error this is
- Status code - The HTTP status code
- Fix suggestions - Specific fix directions
Structure of description
Server returned error: {error message}. Error type: {type}. Status code: {status}. Suggestion: {specific suggestion}
This structured natural language format allows AI to:
- Parse out key information (field names, error types)
- Understand the severity of the problem
- Take action based on the suggestions
Vibe Coding Practical Scenarios
The following demonstrates how AI uses description to automatically fix errors.
Scenario 1: Field Name Typo
You write code in Cursor:
await client.models.users.create({
naem: "Zhang San", // Typo
phone: "13800138000"
});
After running, the SDK throws an error:
LovrabetError {
message: "naem column does not exist",
code: "SERVER_ERROR",
status: 400,
description: "Server returned error: naem column does not exist. Error type: parameter error. Status code: 400. Suggestion: field \"naem\" does not exist, please check if the field name is spelled correctly; use MCP tool to get the correct field list for the dataset"
}
AI's Understanding Process:
- Parses
descriptionand finds it's a "parameter error" - Identifies the problem field as
naem - Sees the suggestion "check if the field name is spelled correctly"
- Infers that
naemmight be a typo forname - Automatically fixes the code
// After AI auto-fix
await client.models.users.create({
name: "Zhang San", // Fixed
phone: "13800138000"
});
Scenario 2: Missing Required Field
await client.models.orders.create({
name: "Order 1",
amount: 100
});
SDK error message:
LovrabetError {
message: "project_id column cannot be empty",
code: "SERVER_ERROR",
status: 400,
description: "Server returned error: project_id column cannot be empty. Error type: parameter error. Status code: 400. Suggestion: field \"project_id\" is required, please ensure this field is provided"
}
AI's Processing Method:
- Identifies that
project_idis a required field - Checks current code and confirms the field is indeed missing
- May query the dataset structure through MCP tools to understand the
project_idtype - Prompts the user to provide the field, or auto-fills it based on context
Scenario 3: Permission/Login Issue
await client.models.users.filter();
SDK error message:
LovrabetError {
message: "Insufficient permissions",
code: "SERVER_ERROR",
status: 401,
description: "Server returned error: Insufficient permissions. Error type: 202. Status code: 401. Suggestion: check if user session has expired, need to re-login; check if appCode has permission to access this dataset; ensure using HTTPS protocol; check for cross-origin issues (CORS)"
}
AI's Investigation Direction:
- Sees 401 status code, identifies as an authentication issue
- Based on suggestions, investigates in order:
- Whether the login session has expired
- appCode permission configuration
- HTTPS protocol
- CORS configuration
- Provides specific troubleshooting steps for the user
Coordination with MCP Tools
description will guide AI to use MCP tools to get more information:
Suggestion: field "xxx" does not exist, please check if the field name is spelled correctly; use MCP tool to get the correct field list for the dataset
When AI sees this suggestion, it will call MCP tools:
// AI calls MCP tool
const datasetInfo = await mcp.tools.get_dataset_detail({
datasetCode: "users"
});
// Get the correct field list
const fields = datasetInfo.fields;
// ["id", "name", "phone", "email", "created_at", ...]
Then AI can:
- Find the correct field names
- Understand which fields are required
- Know the field types and format requirements
This SDK + MCP collaborative architecture enables AI to fully understand and resolve problems.
Error Code Reference
Client Error Codes
| Error Code | Description | description Content |
|---|---|---|
MODEL_NOT_FOUND | Model not found | Lists all available models (datasetCode, alias, name) |
MODEL_INDEX_OUT_OF_RANGE | Model index out of range | Provides valid index range |
CONFIG_NOT_FOUND | Configuration not found | Lists registered configuration names |
APP_CODE_REQUIRED | Missing appCode | Provides configuration example |
TIMEOUT | Request timeout | Current timeout duration, optimization suggestions |
OPENAPI_AUTH_PARAMS_MISSING | OpenAPI authentication parameters missing | Lists missing parameters |
Server Error Codes
| Error Type | HTTP Status Code | description Content |
|---|---|---|
| Parameter error | 400 | Field fix suggestions (required, spelling, format) |
| Insufficient permissions | 401 | Login session, appCode, HTTPS, CORS check suggestions |
| Other errors | Various | Basic information (error type, message, status code) |
safe Function: Try-catch-free Error Handling v1.2.10+
In addition to the traditional try-catch pattern, the SDK also provides a safe function that lets you handle errors elegantly without try-catch.
Basic Usage
import { safe } from "@lovrabet/sdk";
// New style: no try-catch
const { data, error } = await safe(() =>
client.models.users.filter({ where: { status: 'active' } })
);
if (error) {
console.error("Query failed:", error.message, error.description);
return;
}
// Use data
console.log("User list:", data);
Comparison with try-catch
| Aspect | try-catch Pattern | safe Pattern |
|---|---|---|
| Code volume | More (try-catch nesting) | Less (destructuring assignment) |
| Nesting levels | Prone to nesting hell | Flat |
| Error type | Need manual judgment | Always LovrabetError |
| Early return | Need throw or return | Direct return |
| Use cases | Complex error handling logic | Simple conditional checks |
Use Case Comparison
try-catch is suitable for complex scenarios:
try {
const user = await client.models.users.getOne(userId);
const orders = await client.models.orders.filter({ userId });
const stats = await client.api.executeSql('user-stats', { userId });
return { user, orders, stats };
} catch (error) {
if (error instanceof LovrabetError) {
if (error.status === 404) {
throw new Error("User not found");
} else if (error.status === 403) {
throw new Error("Access denied");
}
}
throw error;
}
safe is suitable for simple scenarios:
// Scenario 1: Single API call
const { data, error } = await safe(() => client.models.users.getOne(userId));
if (error) return { success: false, error: error.message };
return { success: true, data };
// Scenario 2: Sequential operations
const result1 = await safe(() => client.models.users.getOne(userId));
if (result1.error) return { error: result1.error.message };
const result2 = await safe(() => client.models.orders.filter({ userId }));
if (result2.error) return { error: result2.error.message };
return { user: result1.data, orders: result2.data };
Type Definition
interface SafeResult<T> {
data: T | null; // Data on success
error: LovrabetError | null; // Error on failure
}
function safe<T>(
fn: Promise<T> | (() => Promise<T>)
): Promise<SafeResult<T>>;
Advanced Usage
Handling concurrent requests:
const [usersResult, ordersResult, statsResult] = await Promise.all([
safe(() => client.models.users.filter()),
safe(() => client.models.orders.filter()),
safe(() => client.api.executeSql('daily-stats')),
]);
// Check individual results
if (usersResult.error) {
console.error("Failed to get users:", usersResult.error.message);
}
if (ordersResult.error) {
console.error("Failed to get orders:", ordersResult.error.message);
}
if (statsResult.error) {
console.error("Failed to get stats:", statsResult.error.message);
}
// Use successful return values
console.log("Users:", usersResult.data);
console.log("Orders:", ordersResult.data);
console.log("Stats:", statsResult.data);
Wrapping error handling utilities:
import { safe, LovrabetError } from "@lovrabet/sdk";
// Unified API call handling
async function handleApiCall<T>(
operation: () => Promise<T>,
errorMessage: string
): Promise<T> {
const { data, error } = await safe(operation);
if (error) {
// Log the error
console.error(`${errorMessage}:`, error.message, error.description);
// Can add logging/reporting here
throw new Error(errorMessage);
}
return data!;
}
// Usage
const users = await handleApiCall(
() => client.models.users.filter({ status: 'active' }),
"Failed to get active users"
);
Backward Compatibility
The safe function does not affect existing code; both patterns can coexist:
// Old code continues to work
try {
const data = await client.models.users.filter();
console.log(data);
} catch (e) {
console.error(e);
}
// New code can also use safe
const { data, error } = await safe(() => client.models.users.filter());
if (error) {
console.error(error);
} else {
console.log(data);
}
Best Practices
Make Error Messages Visible to AI
When Vibe Coding, ensure error messages can be captured by AI tools:
try {
await client.models.users.create(formData);
} catch (error) {
if (error instanceof LovrabetError) {
// Output description, AI tools will read the console
console.error("SDK Error:", error.description);
// Or throw directly to let AI see the full stack
throw error;
}
}
Global Error Handling
Configure global error handling to consistently output AI-friendly information:
const client = createClient({
appCode: "your-app-code",
options: {
onError: (error: LovrabetError) => {
// Output AI-friendly description
console.error("[Lovrabet SDK Error]", error.description);
// 401 auto-redirect to login
if (error.status === 401) {
window.location.href = "/login";
}
},
},
models: [
{ tableName: "users", datasetCode: "xxx", alias: "users" },
],
});
Enhanced Output in Development Environment
Output more information in the development environment:
function handleError(error: LovrabetError) {
if (process.env.NODE_ENV === "development") {
console.group("LovrabetError Debug Info");
console.log("Message:", error.message);
console.log("Code:", error.code);
console.log("Status:", error.status);
console.log("Description:", error.description);
console.log("Response:", JSON.stringify(error.response, null, 2));
console.groupEnd();
}
}
Error Type Determination
By HTTP Status Code
if (error instanceof LovrabetError) {
switch (error.status) {
case 400:
// Parameter error - AI can auto-fix based on description
break;
case 401:
// Authentication failed - need to re-login
break;
case 403:
// Insufficient permissions - check appCode configuration
break;
case 500:
// Server error - need to contact operations
break;
}
}
By Error Code
if (error instanceof LovrabetError) {
switch (error.code) {
case "MODEL_NOT_FOUND":
// See description for available model list
console.log(error.description);
break;
case "SERVER_ERROR":
// See description for specific cause and suggestions
console.log(error.description);
break;
}
}
Summary
Lovrabet SDK's AI-friendly error handling architecture:
| Feature | Description |
|---|---|
| Unified error type | All errors are LovrabetError, easy to handle uniformly |
| AI-understandable description | Contains error cause, type, suggestions; AI can parse directly |
| Targeted fix suggestions | Different error types provide different fix directions |
| MCP tool coordination | Guides AI to use MCP to get more information |
| Support auto-fix | AI can automatically modify code based on information |
In the era of Vibe Coding, good error messages should not only be understandable by humans, but more importantly, by AI so it can help you solve problems.
For more advanced error handling patterns (retry mechanisms, circuit breakers, etc.), see Advanced Features.