we-promise/sure · error · Provider::Anthropic::Error
Model did not invoke #{TOOL_NAME}
Error message
Model did not invoke #{TOOL_NAME} What it means
After the messages API call, AutoCategorizer#extract_categorizations scans response.content for a :tool_use block; if none exists it raises "Model did not invoke report_categorizations". The categorizer relies on Anthropic tool calling (tool_choice forcing the report_categorizations tool), so a response that is plain text, truncated before the tool call (max_tokens/stop_reason), or a refusal means the expected tool block is missing.
Source
Thrown at app/models/provider/anthropic/auto_categorizer.rb:133
def user_message
<<~MESSAGE.strip_heredoc
Here are the user's available categories in JSON:
```json
#{user_categories.to_json}
```
Auto-categorize the following transactions:
```json
#{transactions.to_json}
```
MESSAGE
end
def extract_categorizations(response)
tool_use = Array(response.content).find { |block| block_type(block) == :tool_use }
raise Provider::Anthropic::Error, "Model did not invoke #{TOOL_NAME}" unless tool_use
input = block_input(tool_use)
input = JSON.parse(input) if input.is_a?(String)
categorizations = input.is_a?(Hash) ? (input["categorizations"] || input[:categorizations]) : nil
raise Provider::Anthropic::Error, "Tool call missing categorizations" unless categorizations.is_a?(Array)
categorizations
end
def build_response(categorizations)
categorizations.map do |c|
category_name = c["category_name"] || c[:category_name]
AutoCategorization.new(
transaction_id: c["transaction_id"] || c[:transaction_id],
category_name: normalize_category(category_name)
)
end
endView on GitHub (pinned to e69894adb9)
Solutions
- Retry the call once — transient non-tool responses are common and usually succeed on the second attempt.
- Verify the request actually forces the tool (tool_choice set for report_categorizations) and that the tool schema reaches the API — inspect the Langfuse trace created by auto_categorize.
- Use a stronger/current default model (e.g. claude-sonnet-4-6) or reduce the batch size so the model finishes its tool call within max_tokens.
- If routing through a custom proxy, confirm it forwards tool definitions and tool_choice faithfully.
Example fix
# before
result = Provider::Anthropic::AutoCategorizer.new(client, model: model, transactions: txns, user_categories: cats, family: family).auto_categorize
# after
begin
result = Provider::Anthropic::AutoCategorizer.new(client, model: model, transactions: txns, user_categories: cats, family: family).auto_categorize
rescue Provider::Anthropic::Error => e
raise unless e.message.include?("did not invoke")
retry_once { same_call } # transient: retry, then surface to the job
end Defensive patterns
Strategy: retry
Try / catch
attempts = 0 begin result = provider.auto_categorize(transactions: txns, user_categories: cats, family: family) rescue Provider::Anthropic::Error => e attempts += 1 retry if attempts < 2 # transient tool-less responses usually clear once raise end
Prevention
- Keep batches well under 25 and max_tokens generous so tool calls aren't truncated.
- Default to a current strong model that honors forced tool_choice.
- Check the Langfuse trace when it recurs — stop_reason max_tokens means raise the token cap, not retry.
When it happens
Trigger: The model replies with prose instead of calling the tool; the response is cut off by a max_tokens cap before emitting the tool_use block (stop_reason "max_tokens"); a weak model behind a custom proxy ignores forced tool_choice; prompt text inside transaction memo fields steers the model off-format.
Common situations: Downgrading to a cheaper/legacy model that handles forced tool calls poorly; very long transaction lists consuming output budget; custom OpenAI-compatible-to-Anthropic bridge that drops tool_choice; intermittent provider behavior needing one retry.
Related errors
- Tool call missing categorizations
- Model did not invoke #{TOOL_NAME}
- Model did not invoke #{TOOL_NAME}
- Model did not invoke #{TOOL_NAME}
- Model did not invoke #{TOOL_NAME}
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/b2f46f14138f1530.
Report an issue: GitHub.