{"record":{"id":"e889263f076e21d3","repo":"we-promise/sure","slug":"pdf-content-is-required-e88926","errorCode":null,"errorMessage":"PDF content is required","messagePattern":"PDF content is required","errorType":"exception","errorClass":"Provider::Anthropic::Error","httpStatus":null,"severity":"error","filePath":"app/models/provider/anthropic/pdf_processor.rb","lineNumber":28,"sourceCode":"  # minus a generous envelope reserve, so the encoded request stays under the\n  # limit. Guarding upstream also avoids base64-encoding an over-size blob in\n  # vain (peak heap before the API would reject it).\n  MAX_REQUEST_BYTES = 32 * 1024 * 1024\n  REQUEST_ENVELOPE_BYTES = 1 * 1024 * 1024\n  MAX_PDF_BYTES = (MAX_REQUEST_BYTES - REQUEST_ENVELOPE_BYTES) * 3 / 4\n\n  attr_reader :client, :model, :pdf_content, :langfuse_trace, :family\n\n  def initialize(client, model:, pdf_content:, langfuse_trace: nil, family: nil)\n    @client = client\n    @model = model\n    @pdf_content = pdf_content\n    @langfuse_trace = langfuse_trace\n    @family = family\n  end\n\n  def process\n    raise Provider::Anthropic::Error, \"PDF content is required\" if pdf_content.blank?\n    if pdf_content.bytesize > MAX_PDF_BYTES\n      raise Provider::Anthropic::Error,\n            \"PDF is too large (#{pdf_content.bytesize} bytes); base64-encoded it would exceed Anthropic's 32 MB request limit\"\n    end\n\n    span = langfuse_trace&.span(name: \"process_pdf_api_call\", input: {\n      model: model,\n      pdf_size: pdf_content&.bytesize\n    })\n\n    response = client.messages.create(\n      model: model,\n      max_tokens: max_tokens,\n      system_: instructions,\n      messages: [ { role: \"user\", content: user_content } ],\n      tools: [ output_tool ],\n      tool_choice: { type: \"tool\", name: TOOL_NAME, disable_parallel_tool_use: true }\n    )","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/anthropic/pdf_processor.rb#L10-L46","documentation":"Provider::Anthropic::PdfProcessor#process raises \"PDF content is required\" when pdf_content is blank. The processor base64-encodes the PDF into a document block for the Messages API, so nil/empty content cannot proceed; the guard fires before the Langfuse span and the size check.","triggerScenarios":"process is called with pdf_content: nil or \"\" — an attachment read that returned nil, a document record with empty content, or a caller passing a path/URL string where the binary body is expected.","commonSituations":"Active Storage blob not yet uploaded when the job runs; tempfile lifetime issues; download from a URL returned an empty body; refactor changed the parameter from bytes to something else.","solutions":["Pass the real bytes: attachment.download or File.binread(path).","Validate non-empty content where the upload is accepted (controller/model validation) so the job never gets blank input.","If the source is empty, re-fetch/re-upload the document."],"exampleFix":"# before\nprocessor.process # pdf_content: doc.file_path (String) \n# => PDF content is required\n\n# after\nprocessor = PdfProcessor.new(client, model: model, pdf_content: doc.file.download)\nprocessor.process","handlingStrategy":"validation","validationCode":"content = doc.file.download\nif content.blank?\n  return error(\"Document is empty — re-upload\")\nend\nprovider.process_pdf(pdf_content: content, model: model)","typeGuard":null,"tryCatchPattern":"begin\n  processor.process\nrescue Provider::Anthropic::Error => e\n  doc.mark_failed(reason: e.message)\nend","preventionTips":["Check blob existence and size right after upload, not only at processing time.","Pass binary content, not paths/URLs.","Give documents a failed-state with the provider message so users can re-upload."],"tags":["anthropic","llm","pdf","precondition","document-processing"],"backgroundTag":"missing-required-parameter","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}