Advanced (अपडेट: 3/6/2026)

Claude Code में Error Handling Patterns: boundary पर failure classify करें

Claude Code के साथ API validation, external API, batch jobs और TypeScript error recovery का practical guide.

Claude Code में Error Handling Patterns: boundary पर failure classify करें

Error handling का मतलब हर जगह try-catch जोड़ना नहीं है। जब हम Claude Code से सिर्फ “यह error fix करो” कहते हैं, तो अक्सर patch अस्पष्ट हो जाता है: हर failure 500 बन जाता है, log से कारण नहीं मिलता, और यह साफ नहीं होता कि user input बदले, external service का wait करे, या job फिर से चलाए।

इस article का core pattern है: boundary पर failure classify करो और recovery path साफ लिखो। Boundary वह जगह है जहां application किसी कम predictable चीज से मिलती है: API request body, payment provider, CRM, email service, scheduled job, CSV import या frontend screen। Boundary साफ होगी तो Claude Code को भी साफ instruction मिलेगा: validation error 400, temporary external failure retryable, और batch failure replayable record में।

Recovery से शुरुआत करें

पहला सवाल class name नहीं है। पहला सवाल है: failure के बाद system क्या करे?

BoundaryExampleResponseRecovery
API validationinvalid email, range error, bad JSON400user input सुधारे
External APIpayment, CRM, email down502 या 503retry, pause, temporary failure
Job/Batchreport, CSV import, notificationinternal failure recordsafe rerun, failure queue, alert

सिर्फ message काफी नहीं है। Human पढ़ सकता है, पर program उससे reliable decision नहीं लेता। इसलिए kind, code, retryable, status जैसे machine-readable fields रखें। Claude Code review करते समय इन्हीं fields के आधार पर behavior check कर सकता है।

Copy-paste TypeScript example

यह code Node.js 18+ पर चलता है। Real external API call नहीं होती, क्योंकि fetcher inject किया गया है।

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

Use case 1: API validation

API validation failure अक्सर user-fixable होता है। Invalid email, age सीमा से कम, bad JSON, unknown plan जैसे cases server crash नहीं हैं। Example में parseUser इन्हें validation बनाता है, 400 देता है और retryable: false रखता है।

इससे frontend field दिखा सकता है, backend EMAIL_INVALID से log search कर सकता है, और Claude Code failure-path tests जोड़ सकता है। API testing workflow के लिए Claude Code API testing और testing strategies भी देखें।

Use case 2: external API failure

External services सही code के बावजूद fail हो सकती हैं। Payment, email, CRM, spreadsheet और analytics timeout, rate limit या गलत payload दे सकते हैं। यहां retryable और non-retryable अलग करना जरूरी है।

Example में 5xx को retryable: true माना गया है, लेकिन गलत payload shape को retryable: false। गलत payload को बार-बार retry करने से queue और logs भरते हैं। HTTP response behavior के लिए official MDN Response.ok देखें। Express API में Express error handling भी useful है।

Use case 3: job और batch failure

Job failure screen पर तुरंत नहीं दिखता। Nightly report, CSV import, invoice generation और notification send में failure record बचाना जरूरी है। runJob job name, attempt और retryable state रखता है। Production में इसे structured logs, failure queue, admin screen या alert में भेजें।

सबसे बड़ा सवाल है idempotency। यानी same job दुबारा चलाने पर duplicate side effect न बने। CSV import duplicate rows न बनाए, billing job double charge न करे। Claude Code से syntax के साथ replay safety भी review करवाएं।

Common pitfalls और review prompt

पहला pitfall है catch { return null; }, जो evidence मिटा देता है। दूसरा pitfall है user response में stack trace, SQL, env var या secret leak करना। Security review के लिए Claude Code security audit देखें। तीसरा pitfall है हर error retry करना। Validation और bad payload waiting से ठीक नहीं होते।

Claude Code को यह prompt दें:

इस PR का error handling review करें।
Check:
1. API input, external API, job/batch boundary पर failure classify हुआ है?
2. user-fixable failure गलती से 500 तो नहीं?
3. retryable और non-retryable अलग हैं?
4. response में stack trace, SQL, secret या internal path leak तो नहीं?
5. logs में code, kind, attempt, cause है?
6. कम से कम 3 failure-path tests हैं?
Smallest safe patch और tests suggest करें।

Type narrowing के लिए official TypeScript Narrowing, failure tests के लिए Node.js test runner, और Claude Code settings के लिए Claude Code overview देखें। Test-first approach चाहिए तो Claude Code TDD और debugging techniques साथ पढ़ें।

CTA और Masa का result

Error handling team training के लिए अच्छा topic है, क्योंकि इसमें API, logs, security, tests और operations एक साथ आते हैं। शुरुआत के लिए free cheat sheet लें। Prompts, review checklist और templates चाहिए तो products देखें। Existing repo में Claude Code-friendly rules चाहिए तो training and consulting से API, external integration और batch boundaries को साथ में整理 किया जा सकता है।

Masa ने अपने workflow में validation, external API और batch failures को AppError जैसी shape में लाया। पहले prompt होता था “यह error ठीक करो”; अब instruction है “validation 400 देता है, external retryable देखता है, job attempt रखता है।” Review response, log और test पर केंद्रित हो गया। यह magic architecture नहीं है, लेकिन anonymous 500 से बहुत बेहतर है।

#Claude Code #error handling #design patterns #TypeScript #robustness
मुफ़्त

मुफ़्त PDF: Claude Code cheatsheet

Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.

हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.

Masa

लेखक के बारे में

Masa

Claude Code workflow और team adoption पर काम करने वाला engineer.