we-promise/sure · error · Setting::ValidationError
Anthropic Base URL must be an http(s) URL.
Error message
Anthropic Base URL must be an http(s) URL.
What it means
When the self-hosting settings form submits an anthropic_base_url, the controller strips it and runs URI.parse, then requires the result to be a URI::HTTP (or URI::HTTPS). Any other outcome — a different scheme or a scheme-less string that parses into URI::Generic — raises Setting::ValidationError with the translated '.invalid_anthropic_base_url' message. This guards Provider::Anthropic from being handed an endpoint it cannot call.
Source
Thrown at app/controllers/settings/hostings_controller.rb:186
if hosting_params.key?(:openai_model)
Setting.openai_model = hosting_params[:openai_model]
end
if hosting_params.key?(:openai_json_mode)
Setting.openai_json_mode = hosting_params[:openai_json_mode].presence
end
update_encrypted_setting(:anthropic_access_token)
if hosting_params.key?(:anthropic_base_url)
raw_base_url = hosting_params[:anthropic_base_url].to_s.strip
if raw_base_url.blank?
Setting.anthropic_base_url = nil
else
parsed = URI.parse(raw_base_url) rescue nil
unless parsed.is_a?(URI::HTTP)
raise Setting::ValidationError, t(".invalid_anthropic_base_url")
end
# A custom Anthropic-compatible endpoint requires a model — Provider::Anthropic
# raises without one. Validate the pair together (mirrors the OpenAI branch), using
# the submitted model when present so a blanked model field is caught too.
effective_model =
if hosting_params.key?(:anthropic_model)
hosting_params[:anthropic_model].to_s.strip
else
Setting.anthropic_model.to_s.strip
end
if effective_model.blank?
raise Setting::ValidationError, t(".anthropic_model_required_for_base_url")
end
Setting.anthropic_base_url = raw_base_url
end
end
if hosting_params.key?(:anthropic_model)View on GitHub (pinned to e69894adb9)
Solutions
- Prefix the URL with a scheme: http://host[:port][/path] or https://host[/path]
- Make sure there is no leading/trailing whitespace or invisible characters if you pasted the value (the code strips outer whitespace, but embedded characters still break the parse)
- If you truly need a non-HTTP transport, this settings field cannot express it — put the conversion behind an http front-end
- If the form still fails, reproduce in console: require "uri"; URI.parse(value).is_a?(URI::HTTP) to see exactly what parses
Example fix
# before Setting.anthropic_base_url = "my-anthropic-proxy.internal:8080" # => Setting::ValidationError: Anthropic Base URL must be an http(s) URL. # after Setting.anthropic_base_url = "http://my-anthropic-proxy.internal:8080" # => passes (URI::HTTP), and pair it with a non-blank anthropic_model
Defensive patterns
Strategy: validation
Validate before calling
# Before saving hosting params require "uri" def valid_http_url?(value) parsed = URI.parse(value.to_s.strip) rescue nil parsed.is_a?(URI::HTTP) && parsed.host.present? end url = params[:anthropic_base_url].to_s.strip raise "bad URL" unless url.empty? || valid_http_url?(url)
Type guard
def http_url?(value) URI.parse(value.to_s.strip).is_a?(URI::HTTP) rescue URI::Error, ArgumentError false end
Try / catch
begin # save hosting settings rescue Setting::ValidationError => e # e.message is the translated field error: surface next to the Base URL input flash.now[:alert] = e.message end
Prevention
- Always type the scheme explicitly: http:// or https://
- Prefer copy-paste of a working curl URL over retyping hosts
- Validate with URI.parse(...).is_a?(URI::HTTP) in any script that writes this setting
- Remember the check is format-only; test reachability separately (curl the endpoint)
When it happens
Trigger: Saving the Self-Hosting settings with anthropic_base_url set to a bare host ("my-proxy.internal:8787"), a missing scheme ("api.litebbq.pro/v1"), a wrong scheme ("ftp://…", "anthropic://…"), or trailing whitespace plus scheme-less input. Note the check is on URI class, not reachability: an unreachable but well-formed http:// URL passes this guard and fails later at request time.
Common situations: Pointing the app at an Anthropic-compatible proxy (LiteLLM, claude-code-proxy, a local docker container) and typing the host without http://; copying a URL that got truncated before the scheme; treating a Docker service name ("http://ollama:11434" works, "ollama:11434" does not) as a URL; curl-style muscle memory of omitting the scheme.
Related errors
- Anthropic Model is required when a custom Base URL is set.
- %{field} must be a whole number ≥ %{minimum}.
- External assistant is not configured. Set the URL and token
- {result.error}
- {e.record.errors.full_messages.to_sentence.presence || e.mes
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/c745148df83e56f3.
Report an issue: GitHub.