we-promise/sure · error · Provider::Anthropic::Error
Model did not invoke #{TOOL_NAME}
Error message
Model did not invoke #{TOOL_NAME} What it means
ProviderMerchantEnhancer#extract_enhancements scans the response content for a :tool_use block; if none exists it raises "Model did not invoke report_enhancements". The enhancer forces the report_enhancements tool so merchant website URLs come back as structured JSON; a prose reply, a truncated response, or a refusal ('I cannot browse') leaves the tool block missing.
Source
Thrown at app/models/provider/anthropic/provider_merchant_enhancer.rb:111
- Do NOT include the www. subdomain ("walmart.com", not "www.walmart.com")
- Favor null over false positives; only return a URL when 80%+ confident
- NEVER return a URL for generic or local-only merchants ("Local diner", "Gas station", "ATM withdrawal")
INSTRUCTIONS
end
def user_message
<<~MESSAGE.strip_heredoc
Enhance the following merchants by identifying each one's website URL:
```json
#{merchants.to_json}
```
MESSAGE
end
def extract_enhancements(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)
enhanced = input.is_a?(Hash) ? (input["merchants"] || input[:merchants]) : nil
raise Provider::Anthropic::Error, "Tool call missing merchants" unless enhanced.is_a?(Array)
enhanced
end
def build_response(enhanced)
enhanced.map do |m|
EnhancedMerchant.new(
merchant_id: m["merchant_id"] || m[:merchant_id],
business_url: normalize_value(m["business_url"] || m[:business_url])
)
end
end
View on GitHub (pinned to e69894adb9)
Solutions
- Retry the enhancement call once.
- Verify tool_choice forcing for report_enhancements in the request via the enhance_provider_merchants Langfuse trace.
- Use a current strong model and reduce the merchant batch size if truncation is the cause.
- Confirm custom proxies forward tool definitions and tool_choice.
Example fix
# before
result = enhancer.enhance
# after
begin
result = enhancer.enhance
rescue Provider::Anthropic::Error => e
retry if e.message.include?("did not invoke") && (attempts += 1) < 2
raise
end Defensive patterns
Strategy: retry
Try / catch
attempts = 0
begin
result = provider.enhance_provider_merchants(merchants: batch, family: family)
rescue Provider::Anthropic::Error => e
attempts += 1
retry if attempts < 2 && e.message.include?("did not invoke")
raise
end Prevention
- Use a current strong model and verify tool_choice forcing in the Langfuse trace.
- Keep merchant batches small so tool arguments aren't truncated.
- Retry once before surfacing an error to the user.
When it happens
Trigger: enhance_provider_merchants runs and the model answers in text (e.g. listing URLs inline) instead of calling the tool; max_tokens truncation on large merchant batches; a custom endpoint proxy stripping tool_choice; the model refusing because merchant names look like PII.
Common situations: Weaker model selected in settings; batches near the 25 cap; gateway dropping tool parameters; transient model behavior that succeeds on retry.
Related errors
- Model did not invoke #{TOOL_NAME}
- Model did not invoke #{TOOL_NAME}
- Model did not invoke #{TOOL_NAME}
- Model did not invoke #{TOOL_NAME}
- Tool call missing merchants
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/86945daeff0378b6.
Report an issue: GitHub.