{"record":{"id":"3cc58d74f1d1abc5","repo":"we-promise/sure","slug":"anthropic-model-is-required-when-a-custom-base-url","errorCode":null,"errorMessage":"Anthropic Model is required when a custom Base URL is set.","messagePattern":"Anthropic Model is required when a custom Base URL is set\\.","errorType":"validation","errorClass":"Setting::ValidationError","httpStatus":422,"severity":"error","filePath":"app/controllers/settings/hostings_controller.rb","lineNumber":198,"sourceCode":"      raw_base_url = hosting_params[:anthropic_base_url].to_s.strip\n      if raw_base_url.blank?\n        Setting.anthropic_base_url = nil\n      else\n        parsed = URI.parse(raw_base_url) rescue nil\n        unless parsed.is_a?(URI::HTTP)\n          raise Setting::ValidationError, t(\".invalid_anthropic_base_url\")\n        end\n        # A custom Anthropic-compatible endpoint requires a model — Provider::Anthropic\n        # raises without one. Validate the pair together (mirrors the OpenAI branch), using\n        # the submitted model when present so a blanked model field is caught too.\n        effective_model =\n          if hosting_params.key?(:anthropic_model)\n            hosting_params[:anthropic_model].to_s.strip\n          else\n            Setting.anthropic_model.to_s.strip\n          end\n        if effective_model.blank?\n          raise Setting::ValidationError, t(\".anthropic_model_required_for_base_url\")\n        end\n        Setting.anthropic_base_url = raw_base_url\n      end\n    end\n\n    if hosting_params.key?(:anthropic_model)\n      Setting.anthropic_model = hosting_params[:anthropic_model].presence\n    end\n\n    if hosting_params.key?(:llm_provider)\n      provider = hosting_params[:llm_provider].to_s\n      if %w[openai anthropic].include?(provider)\n        Setting.llm_provider = provider\n      end\n    end\n\n    LLM_NUMERIC_MINIMUMS.each do |key, minimum|\n      next unless hosting_params.key?(key)","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/controllers/settings/hostings_controller.rb#L180-L216","documentation":"A custom Anthropic-compatible endpoint needs an explicit model because Provider::Anthropic raises without one (there is no default model to fall back to when you bypass the official API). The controller validates the pair together: it computes effective_model from the submitted anthropic_model param if present, otherwise from the stored Setting.anthropic_model, and raises Setting::ValidationError with '.anthropic_model_required_for_base_url' when it is blank while a base URL is being set. Using the submitted value means clearing the model field in the same save is caught too, not just an empty stored value.","triggerScenarios":"Submitting anthropic_base_url with an empty anthropic_model field on a fresh install (nothing stored, nothing submitted); submitting both fields but the model field contains only whitespace; submitting the base URL while a previously stored model exists but sending anthropic_model: \"\" in the same request (blanked field is caught); a PATCH that sets only the base URL after the model was previously cleared.","commonSituations":"Self-hosters switching from the official Anthropic API to a proxy (LiteLLM, OpenRouter-style gateway) and filling in the URL first, intending to pick a model later; environment parity issues where staging had a model saved but production does not; form serialization dropping empty fields so the server sees key present but blank.","solutions":["Fill in both fields: set anthropic_model to a model the endpoint serves (e.g. claude-3-5-sonnet-latest or the proxy's model alias) together with the base URL","If you meant to clear the custom endpoint, clear anthropic_base_url instead — a blank base URL is stored as nil and skips the model requirement entirely","Check Setting.anthropic_model in the Rails console to see what the fallback would resolve to before saving","If the pair keeps rejecting, verify with: m = params.key?(:anthropic_model) ? params[:anthropic_model] : Setting.anthropic_model; raise if m.strip.blank?"],"exampleFix":"# before\nSetting.anthropic_base_url = \"http://localhost:4000\"   # model left blank / only whitespace\n# => Setting::ValidationError: Anthropic Model is required when a custom Base URL is set.\n\n# after\nSetting.anthropic_base_url = \"http://localhost:4000\"\nSetting.anthropic_model     = \"claude-3-5-haiku-latest\"","handlingStrategy":"validation","validationCode":"# Before enabling a custom Anthropic endpoint\nurl = params[:anthropic_base_url].to_s.strip\nmodel = params.key?(:anthropic_model) ? params[:anthropic_model].to_s.strip : Setting.anthropic_model.to_s.strip\n\nif url.present? && model.blank?\n  # block the save: pair is incomplete\n  raise \"anthropic_model required with base_url\"\nend","typeGuard":"def complete_anthropic_pair?(url, model)\n  url.to_s.strip.empty? || !model.to_s.strip.empty?\nend","tryCatchPattern":"rescue Setting::ValidationError => e\n  # keep both form values rendered so the user finishes the pair\n  render :edit, status: :unprocessable_entity\nend","preventionTips":["Treat base URL and model as one unit in forms: disable Save until both are filled","When clearing the model, clear the base URL in the same action","Seed a default model via ENV/config for fresh installs that will use a proxy","Automate checks: a smoke test that calls the provider after saving the pair"],"tags":["rails","settings","anthropic","configuration","validation"],"backgroundTag":"missing-required-configuration","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}