Skip to main content

Error Handling

Version Requirement

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

  1. Errors understandable by AI - Structured error messages including error type, cause, and status code
  2. Provide fix suggestions - Specific fix directions for different error types
  3. Guide AI to use tools - When more information is needed, guide AI to call MCP tools to obtain it
  4. 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

PropertyTypePurposeHow AI Uses It
messagestringBrief error messageQuickly understand the problem
codestringError codeDetermine error category
statusnumberHTTP status codeDetermine if it's a client or server issue
descriptionstringAI-friendly detailed descriptionUnderstand error cause, get fix suggestions
responseobjectOriginal responseGet more details when needed
causeunknownOriginal 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:

  1. Error cause - What error the server returned
  2. Error classification - What type of error this is
  3. Status code - The HTTP status code
  4. 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:

  1. Parses description and finds it's a "parameter error"
  2. Identifies the problem field as naem
  3. Sees the suggestion "check if the field name is spelled correctly"
  4. Infers that naem might be a typo for name
  5. 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:

  1. Identifies that project_id is a required field
  2. Checks current code and confirms the field is indeed missing
  3. May query the dataset structure through MCP tools to understand the project_id type
  4. 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:

  1. Sees 401 status code, identifies as an authentication issue
  2. Based on suggestions, investigates in order:
    • Whether the login session has expired
    • appCode permission configuration
    • HTTPS protocol
    • CORS configuration
  3. 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 CodeDescriptiondescription Content
MODEL_NOT_FOUNDModel not foundLists all available models (datasetCode, alias, name)
MODEL_INDEX_OUT_OF_RANGEModel index out of rangeProvides valid index range
CONFIG_NOT_FOUNDConfiguration not foundLists registered configuration names
APP_CODE_REQUIREDMissing appCodeProvides configuration example
TIMEOUTRequest timeoutCurrent timeout duration, optimization suggestions
OPENAPI_AUTH_PARAMS_MISSINGOpenAPI authentication parameters missingLists missing parameters

Server Error Codes

Error TypeHTTP Status Codedescription Content
Parameter error400Field fix suggestions (required, spelling, format)
Insufficient permissions401Login session, appCode, HTTPS, CORS check suggestions
Other errorsVariousBasic 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

Aspecttry-catch Patternsafe Pattern
Code volumeMore (try-catch nesting)Less (destructuring assignment)
Nesting levelsProne to nesting hellFlat
Error typeNeed manual judgmentAlways LovrabetError
Early returnNeed throw or returnDirect return
Use casesComplex error handling logicSimple 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:

FeatureDescription
Unified error typeAll errors are LovrabetError, easy to handle uniformly
AI-understandable descriptionContains error cause, type, suggestions; AI can parse directly
Targeted fix suggestionsDifferent error types provide different fix directions
MCP tool coordinationGuides AI to use MCP to get more information
Support auto-fixAI 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.