Skip to content

Error handling

ℹ️ Version requirement The AI-friendly error handling architecture requires @lovrabet/sdk v1.2.5 or later.

The Lovrabet SDK uses an AI-friendly error handling architecture designed for Vibe Coding (AI-assisted programming). When you use the SDK inside AI coding tools such as Cursor, Claude Code, or Copilot, the AI can read the error messages directly and suggest fixes automatically.

Design philosophy

Why AI-friendly errors?

Traditional error handling speaks only to human developers:

TypeScript
// 传统错误 - AI 难以理解上下文
Error: "project_id列不能为空"

In a Vibe Coding context, the AI needs more context before it can fix the problem for you:

  • What kind of error is this? Bad parameters? A permissions issue?
  • Which field is at fault?
  • How should it be fixed? Any suggestions?
  • How do I look up the correct field information?

The Lovrabet SDK's AI-friendly architecture was designed to answer exactly these questions.

Architecture goals

  1. Errors AI can understand - structured messages carrying error type, cause, and status code
  2. Actionable fix suggestions - concrete remediation directions per error type
  3. Tool guidance - when more information is needed, steer the AI toward the right MCP tools
  4. Auto-fix support - the AI can apply the suggested fixes to your code

The LovrabetError type

Every SDK error is thrown as the unified LovrabetError type:

TypeScript
import { LovrabetError } from "@lovrabet/sdk";

try {
  await client.models.users.create({ name: "张三" });
} catch (error) {
  if (error instanceof LovrabetError) {
    console.log(error.message);     // 错误消息
    console.log(error.code);        // 错误码
    console.log(error.status);      // HTTP 状态码
    console.log(error.description); // AI 友好的详细描述 ⭐
    console.log(error.response);    // 服务端原始响应
    console.log(error.cause);       // 原始错误(v1.2.10+)
  }
}

Error properties

PropertyTypePurposeHow the AI uses it
messagestringShort error messageGets a quick grasp of the problem
codestringError codeClassifies the error
statusnumberHTTP status codeTells client-side from server-side problems
descriptionstringAI-friendly detailed descriptionUnderstands the cause and gets fix suggestions
responseobjectRaw responseDigs into details when needed
causeunknownOriginal error object (v1.2.10+)Traces the error to its source

The AI-friendly description field

description is the core field the SDK designed specifically for AI (v1.2.5+). It contains:

  1. What went wrong - the error the server returned
  2. Error classification - what kind of error this is
  3. Status code - the HTTP status
  4. Fix suggestions - targeted remediation steps

Structure of description

Plain
服务端返回错误: {错误消息}。错误类型: {类型}。状态码: {status}。建议: {具体建议}

This structured natural-language format lets the AI:

  • extract the key facts (field names, error type)
  • gauge how severe the problem is
  • act on the suggestions

Vibe Coding in practice

The scenarios below show how the AI uses description to fix errors automatically.

Scenario 1: a misspelled field name

You write this in Cursor:

TypeScript
await client.models.users.create({
  naem: "张三",  // 拼写错误
  phone: "13800138000"
});

When it runs, the SDK throws:

TypeScript
LovrabetError {
  message: "naem列不存在",
  code: "SERVER_ERROR",
  status: 400,
  description: "服务端返回错误: naem列不存在。错误类型: 参数错误。状态码: 400。建议: 字段 \"naem\" 不存在,请检查字段名是否拼写正确; 使用 MCP 工具获取数据集的正确字段列表"
}

How the AI reasons:

  1. Parses description and identifies a parameter error
  2. Spots the problem field: naem
  3. Reads the suggestion to check the field spelling
  4. Infers that naem is likely a typo for name
  5. Fixes the code automatically
TypeScript
// AI 自动修复后
await client.models.users.create({
  name: "张三",  // 已修复
  phone: "13800138000"
});

Scenario 2: a missing required field

TypeScript
await client.models.orders.create({
  name: "订单1",
  amount: 100
});

SDK error:

TypeScript
LovrabetError {
  message: "project_id列不能为空",
  code: "SERVER_ERROR",
  status: 400,
  description: "服务端返回错误: project_id列不能为空。错误类型: 参数错误。状态码: 400。建议: 字段 \"project_id\" 是必填项,请确保传递该字段"
}

How the AI handles it:

  1. Recognizes that project_id is required
  2. Checks the code and confirms the field is indeed missing
  3. May query the dataset schema via an MCP tool to learn the type of project_id
  4. Asks you for the value, or fills it in from context

Scenario 3: permissions and login issues

TypeScript
await client.models.users.filter();

SDK error:

TypeScript
LovrabetError {
  message: "权限不足",
  code: "SERVER_ERROR",
  status: 401,
  description: "服务端返回错误: 权限不足。错误类型: 202。状态码: 401。建议: 检查用户登录态是否过期,需要重新登录; 检查 appCode 是否有访问该数据集的权限; 确保使用 HTTPS 协议访问; 检查是否存在跨域问题(CORS)"
}

Where the AI looks:

  1. Sees the 401 status and recognizes an authentication problem

  2. Follows the suggestions in order:

    • Is the login state expired?
    • appCode permission configuration
    • HTTPS protocol
    • CORS configuration
  3. Gives you concrete troubleshooting steps


Working with MCP tools

description steers the AI toward MCP tools when more information would help:

Plain
建议: 字段 "xxx" 不存在,请检查字段名是否拼写正确; 使用 MCP 工具获取数据集的正确字段列表

Seeing this suggestion, the AI calls an MCP tool:

TypeScript
// AI 调用 MCP 工具
const datasetInfo = await mcp.tools.get_dataset_detail({
  datasetCode: "users"
});

// 获取正确的字段列表
const fields = datasetInfo.fields;
// ["id", "name", "phone", "email", "created_at", ...]

The AI can then:

  • find the correct field name
  • see which fields are required
  • learn each field's type and format requirements

This SDK + MCP collaboration lets the AI fully understand and resolve the problem.


Error code reference

Client-side error codes

CodeMeaningdescription contains
MODEL_NOT_FOUNDModel not foundA list of all available models (datasetCode, alias, name)
MODEL_INDEX_OUT_OF_RANGEModel index out of rangeThe valid index range
CONFIG_NOT_FOUNDConfiguration not foundThe registered configuration names
APP_CODE_REQUIREDappCode missingA configuration example
TIMEOUTRequest timed outThe current timeout and tuning suggestions
OPENAPI_AUTH_PARAMS_MISSINGOpenAPI auth parameters missingThe missing parameters

Server-side error codes

Error typeHTTP statusdescription contains
Parameter error400Field fix suggestions (required, spelling, format)
Insufficient permissions401Checks for login state, appCode, HTTPS, and CORS
Other errorsvariesBasic info (error type, message, status code)

The safe function: error handling without try-catch v1.2.10+

Besides the traditional try-catch pattern, the SDK provides a safe function that lets you handle errors gracefully without try-catch.

Basic usage

TypeScript
import { safe } from "@lovrabet/sdk";

// 新风格:无 try-catch
const { data, error } = await safe(() =>
  client.models.users.filter({ where: { status: 'active' } })
);

if (error) {
  console.error("查询失败:", error.message, error.description);
  return;
}

// 使用 data
console.log("用户列表:", data);

Compared with try-catch

Aspecttry-catchsafe
Code volumeMore (nested try-catch)Less (destructuring assignment)
NestingEasily spirals into callback hellFlat
Error typeManual checks requiredAlways LovrabetError
Early returnRequires throw or returnJust return
Best forComplex error handling logicSimple conditional checks

When to use which

try-catch for complex flows:

TypeScript
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("用户不存在");
    } else if (error.status === 403) {
      throw new Error("无权访问");
    }
  }
  throw error;
}

safe for simple flows:

TypeScript
// 场景 1:单个 API 调用
const { data, error } = await safe(() => client.models.users.getOne(userId));
if (error) return { success: false, error: error.message };
return { success: true, data };

// 场景 2:顺序操作
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 definitions

TypeScript
interface SafeResult<T> {
  data: T | null;           // 成功时的数据
  error: LovrabetError | null;  // 失败时的错误
}

function safe<T>(
  fn: Promise<T> | (() => Promise<T>)
): Promise<SafeResult<T>>;

Advanced usage

Handling concurrent requests:

TypeScript
const [usersResult, ordersResult, statsResult] = await Promise.all([
  safe(() => client.models.users.filter()),
  safe(() => client.models.orders.filter()),
  safe(() => client.api.executeSql('daily-stats')),
]);

// 检查各自的结果
if (usersResult.error) {
  console.error("获取用户失败:", usersResult.error.message);
}
if (ordersResult.error) {
  console.error("获取订单失败:", ordersResult.error.message);
}
if (statsResult.error) {
  console.error("获取统计失败:", statsResult.error.message);
}

// 使用成功的返回值
console.log("用户:", usersResult.data);
console.log("订单:", ordersResult.data);
console.log("统计:", statsResult.data);

Wrapping error handling utilities:

TypeScript
import { safe, LovrabetError } from "@lovrabet/sdk";

// 统一的 API 调用处理
async function handleApiCall<T>(
  operation: () => Promise<T>,
  errorMessage: string
): Promise<T> {
  const { data, error } = await safe(operation);

  if (error) {
    // 记录错误
    console.error(`${errorMessage}:`, error.message, error.description);
    // 可以在这里添加日志上报
    throw new Error(errorMessage);
  }

  return data!;
}

// 使用
const users = await handleApiCall(
  () => client.models.users.filter({ status: 'active' }),
  "获取活跃用户失败"
);

Backward compatibility

safe does not affect existing code — both patterns can coexist:

TypeScript
// 旧代码继续工作
try {
  const data = await client.models.users.filter();
  console.log(data);
} catch (e) {
  console.error(e);
}

// 新代码也可以用 safe
const { data, error } = await safe(() => client.models.users.filter());
if (error) {
  console.error(error);
} else {
  console.log(data);
}

Best practices

Let the AI see the errors

When Vibe Coding, make sure error output is visible to the AI tool:

TypeScript
try {
  await client.models.users.create(formData);
} catch (error) {
  if (error instanceof LovrabetError) {
    // 输出 description,AI 工具会读取控制台
    console.error("SDK Error:", error.description);

    // 或者直接抛出,让 AI 看到完整堆栈
    throw error;
  }
}

Global error handling

Configure global handling that emits AI-friendly output uniformly:

TypeScript
const client = createClient({
  appCode: "your-app-code",
  options: {
    onError: (error: LovrabetError) => {
      // 输出 AI 友好的描述
      console.error("[Lovrabet SDK Error]", error.description);

      // 401 自动跳转登录
      if (error.status === 401) {
        window.location.href = "/login";
      }
    },
  },
  models: [
    { tableName: "users", datasetCode: "xxx", alias: "users" },
  ],
});

Richer output in development

Output more detail while developing:

TypeScript
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();
  }
}

Inspecting error types

By HTTP status code

TypeScript
if (error instanceof LovrabetError) {
  switch (error.status) {
    case 400:
      // 参数错误 - AI 可以根据 description 自动修复
      break;
    case 401:
      // 认证失败 - 需要重新登录
      break;
    case 403:
      // 权限不足 - 检查 appCode 配置
      break;
    case 500:
      // 服务器错误 - 需要联系运维
      break;
  }
}

By error code

TypeScript
if (error instanceof LovrabetError) {
  switch (error.code) {
    case "MODEL_NOT_FOUND":
      // 查看 description 获取可用模型列表
      console.log(error.description);
      break;
    case "SERVER_ERROR":
      // 查看 description 获取具体原因和建议
      console.log(error.description);
      break;
  }
}

Summary

The Lovrabet SDK's AI-friendly error handling architecture:

FeatureDescription
Unified error typeEvery error is a LovrabetError, easy to handle uniformly
AI-readable descriptionContains cause, type, and suggestions the AI can parse directly
Targeted fix suggestionsEach error type gets its own remediation direction
MCP tool collaborationGuides the AI to fetch more information via MCP
Auto-fix supportThe AI can modify code based on the information

In the Vibe Coding era, a good error message must be readable not just by humans, but by the AI that solves the problem for you.

For more advanced error handling patterns (retries, circuit breakers, and so on), see Advanced features.

基于飞书知识库同步生成,内容以飞书源文档为准