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;
        }
      },
  }),
  ],
});
1 Like

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

1 Like

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 !