LangChain Error Handling: Retry Strategies and Exception Capture Best Practices

This article explains how to make LangChain applications robust by using built‑in retry mechanisms, model fallbacks, tool exception handling, input validation, output‑fixing parsers, and callback monitoring, each illustrated with concrete code examples and practical recommendations.

James' Growth Diary
James' Growth Diary
James' Growth Diary
LangChain Error Handling: Retry Strategies and Exception Capture Best Practices

Why error handling matters

LangChain applications consist of a long call chain (user input → validation → LLM call → tool call → output parsing → result). Every step can fail due to API timeouts, rate limits, malformed tool responses, incorrect JSON output, or network glitches, and a single failure can break the whole pipeline.

Basic: withRetry automatic retry

The Runnable interface provides withRetry, which automatically retries network errors and rate‑limit responses with exponential backoff (1 s → 2 s → 4 s) and throws the last error after the maximum attempts.

import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({ modelName: "gpt-4" });
// Retry up to 3 times with exponential backoff
const modelWithRetry = model.withRetry({
  stopAfterAttempt: 3,
  onFailedAttempt: (error) => {
    console.log(`Attempt ${error.attemptNumber} failed...`);
  },
});
const response = await modelWithRetry.invoke("你好");

Fallback model: withFallbacks

If the primary model is too expensive or unavailable, withFallbacks automatically switches to a cheaper or alternative model.

import { ChatOpenAI } from "@langchain/openai";
const claudeSonnet = new ChatOpenAI({ modelName: "claude-sonnet-4-6" });
const gpt54 = new ChatOpenAI({ modelName: "gpt-5.4" });
const modelWithFallback = claudeSonnet.withFallbacks({ fallbacks: [gpt54] });
const response = await modelWithFallback.invoke("分析这段代码");

Fallback can also be applied to an entire chain by wrapping a primary RunnableSequence with a fallback sequence.

Tool error handling: ToolException

When a tool throws a regular Error, the agent crashes. Throwing ToolException sends the error message back to the LLM, allowing the model to correct and retry.

import { tool } from "@langchain/core/tools";
import { ToolException } from "@langchain/core/tools";
import { z } from "zod";
const divisionTool = tool(async ({ a, b }) => {
  if (b === 0) {
    throw new ToolException("除数不能为零,请换一个数字");
  }
  return `${a} ÷ ${b} = ${a / b}`;
}, {
  name: "division",
  description: "两数相除",
  schema: z.object({ a: z.number().describe("被除数"), b: z.number().describe("除数") }),
});

Input validation

Validate user input before invoking the LLM to avoid unnecessary API calls and provide clearer error messages.

import { RunnableLambda } from "@langchain/core/runnables";
function validateInput(input: { query: string; maxLength?: number }) {
  if (!input.query?.trim()) {
    throw new Error("查询内容不能为空");
  }
  if (input.query.length > 10000) {
    throw new Error("查询内容过长,请控制在 10000 字符以内");
  }
  return input;
}
const chain = RunnableLambda.from(validateInput)
  .pipe(prompt)
  .pipe(model)
  .pipe(outputParser);

Benefits: saves cost, improves UX, and speeds up debugging.

Output parsing failures: OutputFixingParser

If the model returns malformed JSON, OutputFixingParser sends the raw output plus the parsing error back to the LLM for automatic re‑formatting.

import { StructuredOutputParser } from "langchain/output_parsers";
import { OutputFixingParser } from "langchain/output_parsers";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
const baseParser = StructuredOutputParser.fromZodSchema(
  z.object({ name: z.string(), age: z.number(), hobbies: z.array(z.string()) })
);
const fixingParser = OutputFixingParser.fromLLM(new ChatOpenAI({ temperature: 0 }), baseParser);
const result = await fixingParser.parse(badFormattedOutput);

Workflow: parsing failure → send original output + error to LLM → LLM returns corrected format → parse again.

Callback monitoring

Implement a custom BaseCallbackHandler to log LLM, chain, and tool errors and report them to a monitoring system.

import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
class ErrorMonitorHandler extends BaseCallbackHandler {
  name = "ErrorMonitorHandler";
  async handleLLMError(error: Error) {
    console.error(`[LLM Error] ${error.message}`);
    await reportToMonitor({ type: "llm_error", message: error.message, timestamp: Date.now() });
  }
  async handleChainError(error: Error) {
    console.error(`[Chain Error] ${error.message}`);
    await reportToMonitor({ type: "chain_error", message: error.message, timestamp: Date.now() });
  }
  async handleToolError(error: Error) {
    console.error(`[Tool Error] ${error.message}`);
    await reportToMonitor({ type: "tool_error", message: error.message, timestamp: Date.now() });
  }
}
// Register globally
const chain = prompt.pipe(model).pipe(outputParser);
const response = await chain.invoke({ query: "分析这份报告" }, { callbacks: [new ErrorMonitorHandler()] });

Production advice: report errors by type, record full I/O for replay, and set alert thresholds.

Combined production‑grade error handling

By layering input validation, withRetry, withFallbacks, and the callback handler, you obtain a four‑layer protection scheme.

Four‑layer protection architecture: input validation → automatic retry → fallback model → error monitoring
Four‑layer protection architecture: input validation → automatic retry → fallback model → error monitoring
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { RunnableLambda } from "@langchain/core/runnables";

const primaryModel = new ChatOpenAI({ modelName: "claude-sonnet-4-6" }).withRetry({ stopAfterAttempt: 3 });
const fallbackModel = new ChatOpenAI({ modelName: "gpt-5.4" }).withRetry({ stopAfterAttempt: 2 });
const robustModel = primaryModel.withFallbacks({ fallbacks: [fallbackModel] });
const prompt = ChatPromptTemplate.fromTemplate("{input}");
const outputParser = new StringOutputParser();
function validateInput(input: { input: string }) {
  if (!input.input?.trim()) throw new Error("输入不能为空");
  return input;
}
const robustChain = RunnableLambda.from(validateInput)
  .pipe(prompt)
  .pipe(robustModel)
  .pipe(outputParser);
try {
  const result = await robustChain.invoke({ input: "你好" }, { callbacks: [new ErrorMonitorHandler()] });
  console.log(result);
} catch (error) {
  console.error("All retries and fallbacks failed:", error);
  return "服务暂时不可用,请稍后重试";
}

Each layer can be used independently, but together they provide a production‑ready, resilient LangChain application.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AI agentsLangChainError handlingOutputFixingParserToolExceptionwithFallbackswithRetry
James' Growth Diary
Written by

James' Growth Diary

I am James, focusing on AI Agent learning and growth. I continuously update two series: “AI Agent Mastery Path,” which systematically outlines core theories and practices of agents, and “Claude Code Design Philosophy,” which deeply analyzes the design thinking behind top AI tools. Helping you build a solid foundation in the AI era.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.