we-promise/sure · error · Provider::Anthropic::Error

PDF is too large (#{pdf_content.bytesize} bytes); base64-enc

Error message

PDF is too large (#{pdf_content.bytesize} bytes); base64-encoded it would exceed Anthropic's 32 MB request limit

What it means

PdfProcessor#process raises when pdf_content.bytesize exceeds MAX_PDF_BYTES, which is deliberately lower than 32 MiB — (MAX_REQUEST_BYTES - REQUEST_ENVELOPE_BYTES) * 3 / 4 — because this processor base64-encodes the PDF (4/3 expansion) inside the JSON request envelope. The pre-check guarantees the final request stays under Anthropic's 32 MB API limit.

Source

Thrown at app/models/provider/anthropic/pdf_processor.rb:30

  # vain (peak heap before the API would reject it).
  MAX_REQUEST_BYTES = 32 * 1024 * 1024
  REQUEST_ENVELOPE_BYTES = 1 * 1024 * 1024
  MAX_PDF_BYTES = (MAX_REQUEST_BYTES - REQUEST_ENVELOPE_BYTES) * 3 / 4

  attr_reader :client, :model, :pdf_content, :langfuse_trace, :family

  def initialize(client, model:, pdf_content:, langfuse_trace: nil, family: nil)
    @client = client
    @model = model
    @pdf_content = pdf_content
    @langfuse_trace = langfuse_trace
    @family = family
  end

  def process
    raise Provider::Anthropic::Error, "PDF content is required" if pdf_content.blank?
    if pdf_content.bytesize > MAX_PDF_BYTES
      raise Provider::Anthropic::Error,
            "PDF is too large (#{pdf_content.bytesize} bytes); base64-encoded it would exceed Anthropic's 32 MB request limit"
    end

    span = langfuse_trace&.span(name: "process_pdf_api_call", input: {
      model: model,
      pdf_size: pdf_content&.bytesize
    })

    response = client.messages.create(
      model: model,
      max_tokens: max_tokens,
      system_: instructions,
      messages: [ { role: "user", content: user_content } ],
      tools: [ output_tool ],
      tool_choice: { type: "tool", name: TOOL_NAME, disable_parallel_tool_use: true }
    )

    parsed = extract_tool_input(response)

View on GitHub (pinned to e69894adb9)

Solutions

  1. Compress or split the PDF so raw bytes fit the effective base64-adjusted cap (downsample scans, export fewer pages).
  2. If you add an upload size guard, size it to the PdfProcessor limit (the stricter one), not the raw 32 MiB extractor limit.
  3. Retry processing after re-saving the PDF with optimization (qpdf/ghostscript) to shrink it.

Example fix

# before
result = provider.process_pdf(pdf_content: big_pdf)
# => PDF is too large (27053268 bytes); base64-encoded it would exceed Anthropic's 32 MB request limit

# after
if big_pdf.bytesize > Provider::Anthropic::PdfProcessor::MAX_PDF_BYTES
  return error("Compress or split the PDF before processing")
end
result = provider.process_pdf(pdf_content: big_pdf)
Defensive patterns

Strategy: validation

Validate before calling

limit = Provider::Anthropic::PdfProcessor::MAX_PDF_BYTES
if pdf.bytesize > limit
  return error("PDF too large after base64 encoding; compress or split it")
end
provider.process_pdf(pdf_content: pdf)

Try / catch

begin
  processor.process
rescue Provider::Anthropic::Error => e
  doc.mark_failed(reason: e.message)
end

Prevention

When it happens

Trigger: Processing a PDF whose raw size is large enough that its base64 form plus request envelope would exceed 32 MB (roughly >24 MiB raw depending on envelope math); fires before client.messages.create, so no API call is made.

Common situations: Scanned/image-heavy PDFs; yearly brokerage statements; uploads that passed an app-level 32 MB check tuned for the bank-statement extractor (which sends raw bytes, not base64) but exceed this processor's tighter effective limit.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/be8483d7491f26a4. Report an issue: GitHub.