{"record":{"id":"b06bcdd77a97e758","repo":"we-promise/sure","slug":"model-did-not-invoke-tool-name-b06bcd","errorCode":null,"errorMessage":"Model did not invoke #{TOOL_NAME}","messagePattern":"Model did not invoke #(.+?)","errorType":"exception","errorClass":"Provider::Anthropic::Error","httpStatus":null,"severity":"error","filePath":"app/models/provider/anthropic/pdf_processor.rb","lineNumber":146,"sourceCode":"        Classification options:\n          - bank_statement: bank account statements (incl. mobile money / digital wallets)\n          - credit_card_statement: credit card statements\n          - investment_statement: brokerage / investment statements\n          - financial_document: tax forms, receipts, invoices, financial reports\n          - contract: legal agreements, loans, terms of service\n          - other: anything else\n\n        Rules:\n          - Be factual; only report what is clearly visible\n          - If a field is unclear/redacted, return null for it\n          - Do not invent figures or names you cannot read\n          - For statements with many transactions, return the count rather than enumerating them\n      INSTRUCTIONS\n    end\n\n    def extract_tool_input(response)\n      tool_use = Array(response.content).find { |block| block_type(block) == :tool_use }\n      raise Provider::Anthropic::Error, \"Model did not invoke #{TOOL_NAME}\" unless tool_use\n\n      input = block_input(tool_use)\n      input = JSON.parse(input) if input.is_a?(String)\n      input\n    end\n\n    def build_result(parsed)\n      PdfProcessingResult.new(\n        summary: parsed[\"summary\"] || parsed[:summary],\n        document_type: normalize_document_type(parsed[\"document_type\"] || parsed[:document_type]),\n        extracted_data: parsed[\"extracted_data\"] || parsed[:extracted_data] || {}\n      )\n    end\n\n    def normalize_document_type(doc_type)\n      return \"other\" if doc_type.blank?\n\n      normalized = doc_type.to_s.strip.downcase.gsub(/\\s+/, \"_\")","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/anthropic/pdf_processor.rb#L128-L164","documentation":"PdfProcessor#extract_tool_input scans the response for a :tool_use block and raises \"Model did not invoke report_document_analysis\" when none is found. The processor forces the report_document_analysis tool to get structured summary/document_type/extracted_data JSON back; a plain-text analysis, a refusal ('return null if unclear' over-applied), or a max_tokens truncation before the tool block makes extraction impossible.","triggerScenarios":"The model describes the document in prose instead of calling the tool; the tool arguments for a dense statement exceed max_tokens so the block never completes; a custom proxy silently drops tool_choice; image-only or garbled PDFs cause the model to hedge in text.","commonSituations":"Long statements producing huge tool payloads; weak model chosen via settings; gateway translating Anthropic tool calls imperfectly; sporadic provider behavior that a single retry clears.","solutions":["Retry once — the cheapest fix for intermittent tool-less responses.","Inspect the process_pdf_api_call Langfuse span for stop_reason; if max_tokens, raise the cap or send fewer pages per request.","Default to a current strong model (claude-sonnet-4-6) and confirm supports_pdf_processing? passed for it.","Ensure any custom base_url proxy preserves tool definitions and tool_choice."],"exampleFix":"# before\nresult = processor.process\n\n# after\nbegin\n  result = processor.process\nrescue Provider::Anthropic::Error => e\n  retry if e.message.include?(\"did not invoke\") && (tries += 1) < 2\n  raise\nend","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"attempts = 0\nbegin\n  result = processor.process\nrescue Provider::Anthropic::Error => e\n  attempts += 1\n  retry if attempts < 2 && e.message.include?(\"did not invoke\")\n  raise\nend","preventionTips":["Raise max_tokens or shrink the PDF when traces show stop_reason=max_tokens.","Confirm gate supports_pdf_processing? passed for the configured model.","Retry once — most tool-less responses are one-off."],"tags":["anthropic","llm","tool-use","pdf","response-parsing","document-processing"],"backgroundTag":"llm-tool-call-failure","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}