vercel/ai · error · ToolCallRepairError

Error repairing tool call: ${getErrorMessage(cause)}

Error message

Error repairing tool call: ${getErrorMessage(cause)}

What it means

ToolCallRepairError wraps a failure that happened inside `experimental_repairToolCall` while trying to fix a broken tool call (e.g. malformed JSON). The original parse error is preserved as `originalError` and the repair failure as `cause`. It signals the repair path itself threw, not the original defect.

Source

Thrown at packages/ai/src/generate-text/parse-tool-call.ts:79

      }

      let repairedToolCall: LanguageModelV4ToolCall | null = null;

      try {
        repairedToolCall = await repairToolCall({
          toolCall,
          tools,
          inputSchema: async ({ toolName }) => {
            const inputSchema = getOwn(tools, toolName)?.inputSchema;
            return await asSchema(inputSchema).jsonSchema;
          },
          instructions,
          system: instructions,
          messages,
          error,
        });
      } catch (repairError) {
        throw new ToolCallRepairError({
          cause: repairError,
          originalError: error,
        });
      }

      // no repaired tool call returned
      if (repairedToolCall == null) {
        throw error;
      }

      return await refineParsedToolCallInput({
        toolCall: await doParseToolCall({ toolCall: repairedToolCall, tools }),
        refineToolInput,
      });
    }
  } catch (error) {
    // use parsed input when possible
    const parsedInput = await safeParseJSON({ text: toolCall.input });

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Inspect `error.cause` for the real reason the repair function failed and fix that (API key, model availability, prompt).
  2. Make the repair function defensive: wrap its body in try/catch and return the original tool call or null instead of throwing.
  3. Validate that the model used for repair supports tool calling and is correctly configured.

Example fix

// before
experimental_repairToolCall: async ({ toolCall, error }) => {
  const fixed = await repairModel(toolCall); // may throw
  return fixed;
}
// after
experimental_repairToolCall: async ({ toolCall, error }) => {
  try {
    return await repairModel(toolCall);
  } catch (e) {
    return null; // give up gracefully instead of throwing
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (experimental_repairToolCall && typeof experimental_repairToolCall !== 'function') {
  throw new Error('experimental_repairToolCall must be a function');
}

Try / catch

try {
  await generateText({ model, prompt, tools, experimental_repairToolCall });
} catch (e) {
  if (ToolCallRepairError.isInstance(e)) {
    console.error('repair failed:', e.cause, 'original:', e.originalError);
    // fall back to an un-repaired retry or surface a friendly message
  } else throw e;
}

Prevention

When it happens

Trigger: Providing `experimental_repairToolCall` to generateText/streamText and the repair function (often itself an LLM call) throws — network failure, API error, or a bug inside the repair callback.

Common situations: Repair prompt calling a model with invalid/missing API key; repair function throwing on unexpected input; timeout inside the repair LLM call; passing an async repair that rejects.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/7417caf243a9cb04. Report an issue: GitHub.