{"record":{"id":"d3b1922bc1deb3da","repo":"we-promise/sure","slug":"model-does-not-support-pdf-vision-processing-ef","errorCode":null,"errorMessage":"Model does not support PDF/vision processing: #{effective_model}","messagePattern":"Model does not support PDF/vision processing: #(.+?)","errorType":"exception","errorClass":"Provider::Openai::Error","httpStatus":null,"severity":"error","filePath":"app/models/provider/openai.rb","lineNumber":216,"sourceCode":"    end\n  end\n\n  # Can be disabled via ENV for OpenAI-compatible endpoints that don't support vision\n  # Only vision-capable models (gpt-4o, gpt-4-turbo, gpt-4.1, etc.) support PDF input\n  def supports_pdf_processing?(model: @default_model)\n    return false unless ENV.fetch(\"OPENAI_SUPPORTS_PDF_PROCESSING\", \"true\").to_s.downcase.in?(%w[true 1 yes])\n\n    # Custom providers manage their own model capabilities\n    return true if custom_provider?\n\n    # Check if the specified model supports vision/PDF input\n    VISION_CAPABLE_MODEL_PREFIXES.any? { |prefix| model.start_with?(prefix) }\n  end\n\n  def process_pdf(pdf_content:, model: \"\", family: nil)\n    with_provider_response do\n      effective_model = model.presence || @default_model\n      raise Error, \"Model does not support PDF/vision processing: #{effective_model}\" unless supports_pdf_processing?(model: effective_model)\n\n      trace = create_langfuse_trace(\n        name: \"openai.process_pdf\",\n        input: { pdf_size: pdf_content&.bytesize }\n      )\n\n      result = PdfProcessor.new(\n        client,\n        model: effective_model,\n        pdf_content: pdf_content,\n        custom_provider: custom_provider?,\n        langfuse_trace: trace,\n        family: family,\n        max_response_tokens: max_response_tokens\n      ).process\n\n      upsert_langfuse_trace(trace: trace, output: result.to_h)\n","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/openai.rb#L198-L234","documentation":"Raised by Provider::Openai#process_pdf when the effective model is not considered vision/PDF-capable. supports_pdf_processing? short-circuits to false when ENV OPENAI_SUPPORTS_PDF_PROCESSING is not one of true/1/yes (default is 'true'), returns true immediately for custom providers (uri_base set), and otherwise requires the model to start with one of VISION_CAPABLE_MODEL_PREFIXES: gpt-4o, gpt-4-turbo, gpt-4.1, gpt-5, o1, o3. The check runs against the effective model (the model: argument or @default_model), so a globally configured gpt-3.5-turbo or llama-style name on first-party OpenAI trips it.","triggerScenarios":"Setting.openai_model or OPENAI_MODEL set to an older model (gpt-3.5-turbo, gpt-4 non-turbo) and uploading a statement PDF; passing model: \"deepseek-r1\" without a custom uri_base; OPENAI_SUPPORTS_PDF_PROCESSING=false in the environment disabling PDF processing for everyone including custom providers.","commonSituations":"Org pins a cheap legacy model for categorization and PDF uploads then start failing; the feature flag env is flipped off during a cost review and later forgotten; new model names shipping after this prefix list was written (e.g. a future gpt-6) fail the prefix check until the list is updated.","solutions":["Set the model to a vision-capable one for PDF work: model: \"gpt-4.1\" (or gpt-4o/gpt-5/o-series) when calling process_pdf.","Update OPENAI_MODEL / Setting.openai_model if the default itself is legacy.","If the flag was disabled, set OPENAI_SUPPORTS_PDF_PROCESSING=true (or remove it to accept the default).","For genuinely new OpenAI model families, add the prefix to VISION_CAPABLE_MODEL_PREFIXES in app/models/provider/openai.rb:9."],"exampleFix":"# before\nprovider.process_pdf(pdf_content: pdf, model: \"gpt-3.5-turbo\")\n\n# after\nprovider.process_pdf(pdf_content: pdf, model: \"gpt-4.1\")","handlingStrategy":"validation","validationCode":"return unless provider.supports_model?(model)\nreturn unless provider.supports_pdf_processing?(model: model) # cheap pre-check before uploading bytes","typeGuard":"def vision_capable_model?(model)\n  %w[gpt-4o gpt-4-turbo gpt-4.1 gpt-5 o1 o3].any? { |p| model.to_s.start_with?(p) }\nend","tryCatchPattern":"begin\n  provider.process_pdf(pdf_content: bytes, model: model)\nrescue Provider::Openai::Error => e\n  return redirect_to(root_path, alert: \"Model cannot read PDFs; pick a vision-capable model\") if e.message.start_with?(\"Model does not support\")\n  raise\nend","preventionTips":["Gate the PDF upload UI on supports_pdf_processing? instead of failing server-side.","Keep the model prefix list updated when OpenAI ships new families, and default to gpt-4.1.","Remember OPENAI_SUPPORTS_PDF_PROCESSING=false disables PDF processing globally, even for custom providers."],"tags":["openai","pdf","vision-model","model-capability","llm"],"backgroundTag":"unsupported-model-capability","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}