Allow graceful handling of "Tool not found" errors in LangGraph ToolNode to enable Agent self-correction

I am using createAgent with LangGraph, and I am encountering issues when the LLM hallucinates a tool name that does not exist (e.g., it tries to call emo run lint:diff).

Currently, when a tool name is invalid, the runtime throws a “Tool not found” error immediately at the lookup stage (e.g., inside ToolNode). This crashes the execution flow before any middleware has a chance to intervene.

I have defined a middleware using wrapToolCall, but it seems it is never triggered for non-existent tools because the framework throws the error before the middleware stack is invoked (or the middleware expects a valid tool instance).

Error Context:

Plaintext

Tool “npm run lint” not found.
at ToolNode.runTool (…)

This prevents me from implementing Self-Correction logic centrally. I want to catch this error, return a ToolMessage informing the LLM of the mistake, and allow the agent to retry, without the application crashing.

I would like the wrapToolCall middleware (or a similar global middleware hook) to be able to catch “Tool Not Found” scenarios.

The middleware should have the opportunity to intercept the call before the strict lookup validation throws a hard error, or the error should be passed into the middleware’s catch block.

Desired Developer Experience:

TypeScript

const agent = createAgent({
// … config
middleware: [
createMiddleware({
name: “SafeToolHandler”,
wrapToolCall: async (request, next) => {
try {
// I want to be able to catch “Tool not found” here
return await next(request);
} catch (error) {
// If the tool doesn’t exist, I want to handle it here
// and return a ToolMessage to the model for self-correction.
if (error.message.includes(“not found”)) {
return new ToolMessage({
tool_call_id: request.toolCall.id,
name: request.toolCall.name,
content: Error: Tool '${request.toolCall.name}' does not exist. Please check available tools.,
additional_kwargs: { error: true }
});
}
throw error;
}
},
}),
],
});

hi @limerickgds

could you format the post again so that the code part displays correctly? Now it is quite hard to read it :face_with_monocle:

const agent = createAgent({
  middleware: [
    createMiddleware({
      name: “SafeToolHandler”,
      wrapToolCall: async (request, next) => {
        try {
          // I want to be able to catch “Tool not found” here
          return await next(request);
        } catch (error) {
          // If the tool doesn’t exist, I want to handle it here
          // and return a ToolMessage to the model for self-correction.
          if (error.message.includes(“not found”)) {
            return new ToolMessage({
              tool_call_id: request.toolCall.id,
              name: request.toolCall.name,
              content: Error: Tool '${request.toolCall.name}' does not exist.Please check available tools.,
              additional_kwargs: { error: true }
            });
          }
          throw error;
        }
      },
  }),
  ],
});

Are there any good solutions? The requirement is to have the capability to handle LLM error tool calls, for example, by returning them as part of the tool response.

hi @limerickgds I’ll investigate today/tomorrow

hi @limerickgds

to keep you in the loop - I already have some results of my investigation. I will post it here soon.

Hi, do you have any news about this ?

We also need to gracefully handle tool errors.

Thanks !

We also need, pls !

hi guys,

let me get back to this topic today/this weekend. Sorry for keeping you on hold.