{"record":{"id":"e7aa718410304bf1","repo":"Freika/dawarich","slug":"url-must-include-a-host","errorCode":null,"errorMessage":"URL must include a host","messagePattern":"URL must include a host","errorType":"validation","errorClass":"UrlValidatable::BlockedUrlError","httpStatus":null,"severity":"warning","filePath":"app/services/concerns/url_validatable.rb","lineNumber":66,"sourceCode":"    IPAddr.new('127.0.0.0/8'),     # IPv4 loopback\n    IPAddr.new('172.16.0.0/12'),   # RFC1918\n    IPAddr.new('192.0.0.0/24'),    # IETF protocol assignments\n    IPAddr.new('192.168.0.0/16'),  # RFC1918\n    IPAddr.new('198.18.0.0/15'),   # benchmark\n    IPAddr.new('::1/128'),         # IPv6 loopback\n    IPAddr.new('fc00::/7')         # IPv6 ULA\n  ].freeze\n\n  private\n\n  def validate_integration_url!(url)\n    return if url.blank?\n\n    uri = URI.parse(url)\n    unless %w[http https].include?(uri.scheme)\n      raise BlockedUrlError, I18n.t('services.concerns.url_validatable.invalid_scheme', scheme: uri.scheme)\n    end\n    raise BlockedUrlError, I18n.t('services.concerns.url_validatable.host_required') if uri.host.blank?\n\n    # Cloud refuses URLs that embed credentials. Self-hosters legitimately\n    # use http://user:pass@host — homelab Immich behind nginx basic-auth\n    # is a real config we don't want to break.\n    if uri.userinfo.present? && !DawarichSettings.self_hosted?\n      raise BlockedUrlError, I18n.t('services.concerns.url_validatable.embedded_credentials')\n    end\n\n    ip = IPAddr.new(Resolv.getaddress(uri.host))\n    if blocked_ranges.any? { |range| range.include?(ip) }\n      raise BlockedUrlError, I18n.t('services.concerns.url_validatable.blocked_address')\n    end\n  rescue URI::InvalidURIError\n    raise BlockedUrlError, I18n.t('services.concerns.url_validatable.invalid_format')\n  rescue Resolv::ResolvError\n    raise BlockedUrlError, I18n.t('services.concerns.url_validatable.unresolvable_host', host: uri.host)\n  end\n","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/Freika/dawarich/blob/97fad417c5a11b0eb11157890635e015723a2e97/app/services/concerns/url_validatable.rb#L48-L84","documentation":"Raised as BlockedUrlError by validate_integration_url! when the URI parses and has an acceptable http/https scheme but uri.host is blank. This happens for URLs whose authority component is missing: 'https:///path', 'https://:8080/x', or scheme-only strings like 'https://' — the parser accepts them but there is no host to resolve or connect to.","triggerScenarios":"Saving 'https://' plus only a path or port ('https:///api', 'https://:2283'), a URL built by string interpolation where the host variable was empty (\"https://#{host}:2283\" with host=''), or user input that is just the scheme.","commonSituations":"Settings forms where the host field is optional and left blank while the client auto-prepends https://, template/env interpolation producing empty hosts, copy-paste that drops the hostname, trailing-punctuation hosts that URI.parse pushes into the path.","solutions":["Re-enter the URL with a real hostname: 'https://immich.example.com:2283'.","If the URL is assembled from parts, guard each part is non-empty before building, or fail the save in the form.","Inspect URI.parse(url) in a console (scheme/host/port/path) to see where the host went.","Make the host field required and validated client-side."],"exampleFix":"# before\nbase = ENV['IMMICH_HOST'] # nil in this env\nurl = \"https://#{base}:2283\"     # => \"https://:2283\", host nil\n\n# after\nbase = ENV.fetch('IMMICH_HOST') { raise 'IMMICH_HOST not set' }\nurl = \"https://#{base}:2283\"    # host present","handlingStrategy":"validation","validationCode":"uri = URI.parse(url.to_s)\nuri.host.present? || errors.add(:url, 'host missing')","typeGuard":"def url_with_host?(s)\n  u = URI.parse(s.to_s)\n  %w[http https].include?(u.scheme) && u.host.present?\nrescue URI::InvalidURIError\n  false\nend","tryCatchPattern":"begin\n  validate_integration_url!(url)\nrescue BlockedUrlError => e\n  errors.add(:url, e.message)\nend","preventionTips":["Build URLs from validated parts; never interpolate possibly-empty variables into the authority.","Require the host field in integration forms.","Test URL templates with missing parts in your suite."],"tags":["url-validation","input-validation","integrations","ruby"],"backgroundTag":"malformed-url","analyzedSha":"97fad417c5a11b0eb11157890635e015723a2e97","analyzedAt":"2026-08-21T17:04:17.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}