{"record":{"id":"efd5926605cea6e2","repo":"Freika/dawarich","slug":"invalid-url-format","errorCode":null,"errorMessage":"Invalid URL format","messagePattern":"Invalid URL format","errorType":"validation","errorClass":"UrlValidatable::BlockedUrlError","httpStatus":null,"severity":"warning","filePath":"app/services/concerns/url_validatable.rb","lineNumber":80,"sourceCode":"    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\n  def blocked_ranges\n    if DawarichSettings.self_hosted?\n      ALWAYS_BLOCKED_RANGES\n    else\n      ALWAYS_BLOCKED_RANGES + CLOUD_ONLY_BLOCKED_RANGES\n    end\n  end\nend\n","sourceCodeStart":62,"sourceCodeEnd":93,"githubUrl":"https://github.com/Freika/dawarich/blob/97fad417c5a11b0eb11157890635e015723a2e97/app/services/concerns/url_validatable.rb#L62-L93","documentation":"Raised as BlockedUrlError when URI.parse raises URI::InvalidURIError while parsing the integration URL. Ruby's URI parser is strict: spaces, unescaped braces/brackets/pipes, non-ASCII characters, or control bytes make it throw. This catches malformed input before scheme/host checks run.","triggerScenarios":"URLs containing literal spaces ('https://my immich.com'), unencoded query strings ('https://h/api?key=a b&x=[1]'), copied unicode (full-width colon, smart quotes), trailing garbage like 'https://host.com/\\u{200b}' (zero-width space), or 'https://host#frag ment'.","commonSituations":"Copy-paste from chat apps or docs introducing smart quotes/zero-width chars, users typing URLs with spaces, values round-tripped through JSON with encoding damage, URLs with IPv6 literals that need brackets ('http://[::1]:2283' is fine but 'http://::1:2283' throws).","solutions":["Re-enter or sanitize the URL: strip whitespace/control characters and percent-encode spaces and unsafe characters (Addressable::URI.normalize or ERB::Util.url_encode for parts).","Paste into a browser address bar first — if the browser also struggles or rewrites it, the URL itself is malformed.","Check for invisible characters: url.each_char.select { |c| c.ord > 126 } in a console.","On the client, trim and validate with a URL parser before submit."],"exampleFix":"# before\nurl = \"https://immich.example.com/api key=1\" # space -> URI::InvalidURIError -> BlockedUrlError\n\n# after\nrequire 'addressable/uri'\nurl = Addressable::URI.normalize_component(\"https://immich.example.com/api key=1\")\n# => \"https://immich.example.com/api%20key=1\"","handlingStrategy":"validation","validationCode":"require 'addressable/uri'\nnormalized = Addressable::URI.parse(url.to_s).normalize.to_s # raises Addressable::URI::InvalidURIError on garbage","typeGuard":"def parseable_url?(s)\n  URI.parse(s.to_s)\n  true\nrescue URI::InvalidURIError, URI::BadURIError\n  false\nend","tryCatchPattern":"begin\n  validate_integration_url!(url)\nrescue BlockedUrlError => e\n  errors.add(:url, 'URL is malformed - check for spaces and special characters')\nend","preventionTips":["Trim and normalize pasted URLs (Addressable::URI.normalize_component) before storage.","Reject URLs containing spaces or control characters client-side.","Beware smart quotes and zero-width characters from chat/doc copy-paste."],"tags":["url-validation","uri-parsing","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"}