Freika/dawarich · warning · UrlValidatable::BlockedUrlError
Invalid URL scheme: %{scheme}
Error message
Invalid URL scheme: %{scheme} What it means
Raised as BlockedUrlError by Imports/UrlValidatable#validate_integration_url! when the parsed URL's scheme is anything other than http or https. Typical offenders: 'ftp://', 'file://', 'webdav://', a bare 'host/path' that URI.parse gives a nil scheme for, or typos like 'http//host'. It fires before DNS resolution, so it is purely a lexical scheme check.
Source
Thrown at app/services/concerns/url_validatable.rb:64
IPAddr.new('10.0.0.0/8'), # RFC1918
IPAddr.new('100.64.0.0/10'), # CGNAT (Tailscale uses this)
IPAddr.new('127.0.0.0/8'), # IPv4 loopback
IPAddr.new('172.16.0.0/12'), # RFC1918
IPAddr.new('192.0.0.0/24'), # IETF protocol assignments
IPAddr.new('192.168.0.0/16'), # RFC1918
IPAddr.new('198.18.0.0/15'), # benchmark
IPAddr.new('::1/128'), # IPv6 loopback
IPAddr.new('fc00::/7') # IPv6 ULA
].freeze
private
def validate_integration_url!(url)
return if url.blank?
uri = URI.parse(url)
unless %w[http https].include?(uri.scheme)
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.invalid_scheme', scheme: uri.scheme)
end
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.host_required') if uri.host.blank?
# Cloud refuses URLs that embed credentials. Self-hosters legitimately
# use http://user:pass@host — homelab Immich behind nginx basic-auth
# is a real config we don't want to break.
if uri.userinfo.present? && !DawarichSettings.self_hosted?
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.embedded_credentials')
end
ip = IPAddr.new(Resolv.getaddress(uri.host))
if blocked_ranges.any? { |range| range.include?(ip) }
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.blocked_address')
end
rescue URI::InvalidURIError
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.invalid_format')
rescue Resolv::ResolvError
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.unresolvable_host', host: uri.host)View on GitHub (pinned to 97fad417c5)
Solutions
- Fix the stored URL to start with http:// or https:// (e.g. 'https://immich.example.com').
- If the input is a bare host, have the UI prepend a default scheme or normalize client-side before submitting.
- If the scheme looks present but still fails, print URI.parse(url).scheme to see what Ruby actually extracted (nil, 'ftp', garbage).
- Add a client-side pattern check like \Ahttps?:// before allowing save.
Example fix
# before url = 'immich.lan:2283' # URI scheme is nil validate_integration_url!(url) # -> BlockedUrlError: Invalid URL scheme # after url = 'http://immich.lan:2283' validate_integration_url!(url) # scheme 'http' passes
Defensive patterns
Strategy: validation
Validate before calling
require 'uri' uri = URI.parse(url.to_s) uri.scheme.in?(%w[http https]) # gate before save
Type guard
def http_url?(s) u = URI.parse(s.to_s) %w[http https].include?(u.scheme) && u.host.present? rescue URI::InvalidURIError false end
Try / catch
begin validate_integration_url!(url) rescue BlockedUrlError => e errors.add(:url, e.message) end
Prevention
- Validate scheme client-side with a \Ahttps?:// pattern before allowing the form to save.
- Auto-prepend https:// when the user typed a bare host.
- Store the original raw value in the error report so typos are obvious.
When it happens
Trigger: User saves an integration URL (Immich, PhotoPrism, OwnTracks endpoint) typed as 'immich.example.com' without a scheme (scheme is nil), 'ftp://server/export', or with a malformed prefix like 'http//:'. Also API clients posting url: 'localhost:2283' without http://.
Common situations: Users pasting hostnames copied from docs that omit the protocol, mobile clients constructing URLs from a host field, typos when editing self-hosted integration settings, URLs with trailing spaces or unicode characters that break URI.parse's scheme detection.
Related errors
- URL must include a host
- URL must not embed credentials (user:pass@host)
- URL resolves to a blocked address
- Invalid URL format
- Could not resolve hostname: %{host}
AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21).
Data as JSON: /api/errors/e4a4ba8edb4c2160.
Report an issue: GitHub.