ollama - ✅(Solved) Fix Warn on tool name mismatch when tool_choice: "required" &/ support case-insensitive tool name matching [1 pull requests, 8 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
ollama/ollama#14967Fetched 2026-04-08 01:03:45
View on GitHub
Comments
8
Participants
3
Timeline
9
Reactions
0
Author
Timeline (top)
commented ×8cross-referenced ×1

Error Message

When using tool_choice: "required" with the OpenAI-compatible /v1/chat/completions endpoint, if the system prompt instructs the model to call a tool name that doesn't exactly match any registered tool definition, the model silently returns this resp: finish_reason: "stop", instead of emitting tool calls. There is no warning or error.

  • Log a warning server-side (ex: WARN: model attempted to call 'get-orders-at-risk-count' but no matching tool found in registered tools)

Fix Action

Fixed

PR fix notes

PR #14995: tools: warn when model tool call names don't match registered tools

Description (problem / solution / changelog)

Fixes #14967.

When tools are registered but the model responds with a function name that doesn't match any of them (e.g. get-orders-at-risk-count vs GetOrdersAtRiskCount), the response just comes back with finish_reason: "stop" and no indication of what went wrong. This makes it really hard to debug, especially when tool names are transformed between systems.

This adds a server-side slog.Warn that fires when the generic tool parser finishes without matching any registered tools but finds tool-call-like JSON in the model output. The warning includes both the name the model tried to call and the list of registered tool names, so you can immediately spot the mismatch.

Example log output:

WARN model attempted tool calls that did not match any registered tools attempted=["get-orders-at-risk-count"] registered=["GetOrdersAtRiskCount"]

Only affects the generic parser path — the harmony parser already has its own warning via OriginalFromConverted. No changes to API behavior or response format.

Changed files

  • server/routes.go (modified, +6/-0)
  • tools/tools.go (modified, +78/-0)
  • tools/tools_test.go (modified, +103/-0)

Code Example

Request: tool_choice: "required", tools: [GetOrdersAtRiskCount, ...], system prompt says "Call get-orders-at-risk-count"
Response: finish_reason: "stop", content: "I don't have access to tools...", tool_calls: none
RAW_BUFFERClick to expand / collapse

When using tool_choice: "required" with the OpenAI-compatible /v1/chat/completions endpoint, if the system prompt instructs the model to call a tool name that doesn't exactly match any registered tool definition, the model silently returns this resp: finish_reason: "stop", instead of emitting tool calls. There is no warning or error.

This came up in this issue Tool calls silently drop with large system prompts (~1600+ tokens) where I spent time trying to figure out what was going on, and I thought it was an Ollama bug, but was actually a casing mismatch btw tool names in my system prompt (kebab-case: get-orders-at-risk-count) and the registered tool definitions (PascalCase: GetOrdersAtRiskCount). This is easy to hit when tool names are transformed between systems.

Either of the following ideas would be helpful:

  1. emit a warning when tool names don't match

When tool_choice: "required" is set and the model's resp references a function name that doesn't match any tool in the tools array, Ollama could:

  • Log a warning server-side (ex: WARN: model attempted to call 'get-orders-at-risk-count' but no matching tool found in registered tools)
  • Optionally include a warning in the API response

This would make debugging significantly faster.

  1. Support case-insensitive / normalized tool name matching

Apply normalization when matching tool names so that get-orders-at-risk-count, GetOrdersAtRiskCount, and getordersatriskcount all resolve to the same tool. This could be done by the following:

  • Strip hyphens/underscores and compare case-insensitively
  • Or use a simple fuzzy match on registered tool names

Currently,

Request: tool_choice: "required", tools: [GetOrdersAtRiskCount, ...], system prompt says "Call get-orders-at-risk-count"
Response: finish_reason: "stop", content: "I don't have access to tools...", tool_calls: none

Expected behavior: Either

  • A warning is emitted that the model tried to call a tool that doesn't exist
  • Or the name is fuzzy-matched to the correct registered tool and the tool call succeeds

Issue for ref that prompted this issue to be created.

extent analysis

Fix Plan

To address the issue of silent failures when tool names don't match, we can implement case-insensitive tool name matching. Here are the steps:

  • Modify the tool name matching logic to strip hyphens and underscores, and compare case-insensitively.
  • Add a warning mechanism to log and optionally return a warning in the API response when a tool name mismatch is detected.

Example Code

import re

def normalize_tool_name(tool_name):
    """Normalize a tool name by stripping hyphens and underscores, and converting to lower case."""
    return re.sub(r'[-_]', '', tool_name).lower()

def match_tool_name(tool_name, registered_tools):
    """Match a tool name against a list of registered tools, using case-insensitive matching."""
    normalized_tool_name = normalize_tool_name(tool_name)
    for registered_tool in registered_tools:
        if normalize_tool_name(registered_tool) == normalized_tool_name:
            return registered_tool
    return None

def process_tool_choice(tool_choice, tools, system_prompt):
    """Process the tool choice and system prompt, emitting a warning if a tool name mismatch is detected."""
    if tool_choice == "required":
        tool_name = extract_tool_name_from_system_prompt(system_prompt)
        matched_tool = match_tool_name(tool_name, tools)
        if matched_tool is None:
            # Log a warning and optionally return a warning in the API response
            print(f"WARN: model attempted to call '{tool_name}' but no matching tool found in registered tools")
            # Return a warning in the API response
            return {"warning": f"Tool '{tool_name}' not found", "tool_calls": []}
        else:
            # Proceed with the matched tool
            return {"tool_calls": [matched_tool]}
    else:
        # Handle other tool choice values
        pass

Verification

To verify that the fix worked, test the following scenarios:

  • Test a system prompt with a tool name that exactly matches a registered tool definition.
  • Test a system prompt with a tool name that has a different case or formatting (e.g. kebab-case vs PascalCase) than a registered tool definition.
  • Verify that a warning is emitted and returned in the API response when a tool name mismatch is detected.

Extra Tips

  • Consider using a more robust fuzzy matching algorithm, such as Levenshtein distance or Jaro-Winkler distance, to match tool names.
  • Add additional logging and monitoring to detect and diagnose tool name mismatch issues.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

ollama - ✅(Solved) Fix Warn on tool name mismatch when tool_choice: "required" &/ support case-insensitive tool name matching [1 pull requests, 8 comments, 3 participants]