Advanced (更新: 2026/6/3)

Claude Code 错误处理模式:在边界分类失败并设计恢复路径

用 Claude Code 设计可维护的错误处理。涵盖 API 校验、外部 API 失败、批处理失败与 TypeScript 实现。

Claude Code 错误处理模式:在边界分类失败并设计恢复路径

错误处理不是到处添加try-catch。如果只是让 Claude Code“把报错修一下”,它很容易把所有失败都变成500,或者在日志里留下难以检索的字符串。真正有用的设计,是在系统边界先判断失败的种类,再写清楚恢复方式。

这里的边界,指的是应用与外部世界接触的位置:API 请求体、第三方支付、CRM、邮件服务、定时任务、CSV 导入、前端页面等。边界越清楚,Claude Code 越容易做正确的修改。例如,用户输入错误返回400;第三方服务临时不可用可以重试;批处理失败要留下可重跑的记录。

本文把错误处理解释成一个适合初学者的模式:在边界分类失败,并明确恢复路径。你会看到可复制运行的 TypeScript 示例、三个真实用例、常见坑、Claude Code 审查提示词,以及面向培训和商品转化的 CTA。

先从恢复方式倒推错误类型

不要先纠结类名叫AppError还是DomainError。先问:系统下一步应该怎么做?

边界常见失败返回方式恢复方式
API 输入校验邮箱格式错误、年龄越界、JSON 结构错误400让用户修正输入
外部 API支付、CRM、邮件供应商不可用502503重试、暂停流程、提示临时失败
Job/Batch夜间报表、CSV 导入、通知发送失败内部失败记录安全重跑、失败队列、人工通知

只保存message是不够的。人能读懂,但程序很难做判断。建议至少保留kindcoderetryablestatus。这样 Claude Code 在审查时可以检查行为,而不是猜测字符串含义。

可复制运行的 TypeScript 示例

下面的示例可以在 Node.js 18 以上运行。它没有真正访问外部网络,而是注入一个假的fetcher来稳定复现失败。

npm install -D tsx typescript
npx tsx error-patterns-demo.ts
type Kind = "validation" | "external" | "job";
type AppError = { kind: Kind; code: string; message: string; retryable: boolean; status: number; detail?: unknown };
type Result<T> = { ok: true; value: T } | { ok: false; error: AppError };

const ok = <T>(value: T): Result<T> => ({ ok: true, value });
const fail = <T>(error: AppError): Result<T> => ({ ok: false, error });

function parseUser(body: unknown): Result<{ email: string; age: number }> {
  if (typeof body !== "object" || body === null) {
    return fail({ kind: "validation", code: "BODY_REQUIRED", message: "body must be an object", retryable: false, status: 400 });
  }
  const data = body as Record<string, unknown>;
  if (typeof data.email !== "string" || !data.email.includes("@")) {
    return fail({ kind: "validation", code: "EMAIL_INVALID", message: "email is invalid", retryable: false, status: 400 });
  }
  if (typeof data.age !== "number" || data.age < 13) {
    return fail({ kind: "validation", code: "AGE_INVALID", message: "age must be 13 or greater", retryable: false, status: 400 });
  }
  return ok({ email: data.email, age: data.age });
}

async function callPartner(fetcher: () => Promise<Response>): Promise<Result<{ id: string }>> {
  try {
    const response = await fetcher();
    if (!response.ok) {
      return fail({ kind: "external", code: "PARTNER_HTTP", message: `partner returned ${response.status}`, retryable: response.status >= 500, status: 503 });
    }
    const json = (await response.json()) as { id?: unknown };
    if (typeof json.id !== "string") {
      return fail({ kind: "external", code: "PARTNER_PAYLOAD", message: "partner payload is invalid", retryable: false, status: 502, detail: json });
    }
    return ok({ id: json.id });
  } catch (error) {
    return fail({ kind: "external", code: "PARTNER_UNREACHABLE", message: "partner is unreachable", retryable: true, status: 503, detail: error });
  }
}

async function runJob<T>(name: string, work: () => Promise<T>, retries = 2): Promise<Result<T>> {
  for (let attempt = 1; attempt <= retries + 1; attempt += 1) {
    try {
      return ok(await work());
    } catch (error) {
      if (attempt <= retries) continue;
      return fail({ kind: "job", code: "JOB_FAILED", message: `${name} failed`, retryable: true, status: 500, detail: { attempt, error } });
    }
  }
  return fail({ kind: "job", code: "JOB_FAILED", message: `${name} failed`, retryable: true, status: 500 });
}

console.log(parseUser({ email: "bad", age: 10 }));
console.log(await callPartner(async () => new Response("down", { status: 503 })));
console.log(await runJob("daily-report", async () => ({ exportedRows: 42 })));

用例1: API 输入校验

API 校验失败通常是用户可以修正的失败。邮箱格式不对、年龄太小、JSON 不是对象、套餐名称不存在,这些都不应该被包装成服务器崩溃。示例里的parseUser在请求进入业务逻辑之前就返回validation,并设置status: 400retryable: false

这会带来三个好处。前端可以根据字段提示用户;后端日志可以用EMAIL_INVALID搜索;Claude Code 可以围绕失败路径补测试,而不是只测正常路径。和Claude Code API 测试指南一起使用时,输入边界会更稳定。

用例2: 外部 API 失败

外部服务即使在你的代码正确时也会失败。支付、邮件、CRM、Google Sheets、Slack 都可能超时、限流或返回不符合约定的数据。这里必须区分“可以重试”和“不应该重试”。

示例里的callPartner5xx类失败标记为retryable: true,但把响应结构错误标记为retryable: false。如果对错误结构无限重试,只会制造更多日志噪音。判断 HTTP 响应时可以参考官方的MDN Response.ok。如果项目使用 Express,也应确认Express error handling里关于错误中间件位置的说明。

用例3: Job/Batch 失败

批处理失败的危险在于,用户往往已经离开页面。夜间报表、CSV 导入、账单生成、通知发送都需要留下可重跑的线索。runJob记录了任务名、最终尝试次数和可重试性。真实项目里,这些信息应该进入结构化日志、失败队列、管理后台或告警系统。

最重要的问题是幂等性。幂等性是指同一个操作重复执行也不会造成额外副作用。如果 CSV 导入会重复插入数据,或者账单任务会重复扣款,那么重试逻辑本身就是风险。让 Claude Code 检查“能否安全重跑”,比只检查语法更重要。

常见坑与 Claude Code 审查提示词

第一个坑是catch { return null; }。这会把证据删掉,后续无法追查。第二个坑是把 SQL 名称、环境变量、堆栈、密钥片段返回给用户。安全层面的检查可以参考Claude Code 安全审计自动化。第三个坑是对所有失败都重试。校验错误和错误响应结构通常不会因为等待而变好。

可以把下面的提示词交给 Claude Code:

请审查这个 PR 的错误处理。
重点:
1. 是否在 API 输入、外部 API、Job/Batch 边界分类失败
2. 用户可修正的失败是否错误地返回 500
3. retryable 和 non-retryable 是否分开
4. 响应是否泄露 stack trace、SQL、密钥或内部路径
5. 日志是否包含 code、kind、attempt、cause
6. 是否至少覆盖 3 个失败路径测试
请给出最小修改和对应测试。

TypeScript 的判别联合与类型收窄可以参考官方TypeScript Narrowing,失败路径测试可以参考Node.js test runner。如果想用测试先固定失败,再让 Claude Code 修复,可以继续阅读Claude Code TDD 实践调试技巧指南。Claude Code 本身的项目记忆与设置可从Claude Code overview确认。

CTA 与 Masa 的试用结果

错误处理非常适合做成团队培训,因为它连接了 API、日志、安全、测试和运维。如果你想先自己试,可以从免费速查表开始。需要提示词、审查清单和模板时,可以看商品列表。如果要把既有项目的错误处理整理成 Claude Code 可维护的规则,可以通过Claude Code 培训与导入咨询一起梳理。

Masa 在自己的项目里把输入校验、外部 API、批处理失败统一到类似AppError的形状后,给 Claude Code 的指示明显变短了。以前会写“把这个错误修好”,现在可以写“validation 返回 400,external 根据 retryable 判断是否重试,job 保留 attempt”。审查范围也自然收敛到响应、日志、测试三处。它不是万能架构,但比到处都是匿名500更容易运营。

#Claude Code #错误处理 #设计模式 #TypeScript #健壮性
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。