{"record":{"id":"df43768469a4261f","repo":"carrierwaveuploader/carrierwave","slug":"couldn-t-parse-url-source","errorCode":null,"errorMessage":"couldn't parse URL: #{source}","messagePattern":"couldn't parse URL: #(.+?)","errorType":"exception","errorClass":"CarrierWave::DownloadError","httpStatus":null,"severity":"error","filePath":"lib/carrierwave/downloader/base.rb","lineNumber":75,"sourceCode":"      end\n\n      ##\n      # Processes the given URL by parsing it, and escaping if necessary. Public to allow overriding.\n      #\n      # === Parameters\n      #\n      # [url (String)] The URL where the remote file is stored\n      #\n      def process_uri(source)\n        uri = Addressable::URI.parse(source)\n        uri.host = uri.normalized_host\n        # Perform decode first, as the path is likely to be already encoded\n        uri.path = encode_path(decode_uri(uri.path)) if uri.path =~ CarrierWave::Utilities::Uri::PATH_UNSAFE\n        uri.query = encode_non_ascii(uri.query) if uri.query\n        uri.fragment = encode_non_ascii(uri.fragment) if uri.fragment\n        URI.parse(uri.to_s)\n      rescue URI::InvalidURIError, Addressable::URI::InvalidURIError\n        raise CarrierWave::DownloadError, \"couldn't parse URL: #{source}\"\n      end\n\n      ##\n      # If this returns true, SSRF protection will be bypassed.\n      # You can override this if you want to allow accessing specific local URIs that are not SSRF exploitable.\n      #\n      # === Parameters\n      #\n      # [uri (URI)] The URI where the remote file is stored\n      #\n      # === Examples\n      #\n      #     class CarrierWave::Downloader::CustomDownloader < CarrierWave::Downloader::Base\n      #       def skip_ssrf_protection?(uri)\n      #         uri.hostname == 'localhost' && uri.port == 80\n      #       end\n      #     end\n      #","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/carrierwaveuploader/carrierwave/blob/b5f0abe10ecf6500309fc83e0e8969cf57ba690e/lib/carrierwave/downloader/base.rb#L57-L93","documentation":"Raised as CarrierWave::DownloadError by CarrierWave::Downloader::Base#process_uri when the source string cannot be parsed as a URI. process_uri first parses with Addressable::URI, normalizes/encodes the path, query and fragment, then re-parses with URI.parse; if either parse raises URI::InvalidURIError or Addressable::URI::InvalidURIError, the source is rejected.","triggerScenarios":"Calling uploader.download! or assigning a remote URL whose string is not a valid URI: unencoded spaces in the path ('http://example.com/my file.jpg'), stray characters or incomplete URLs ('not a url', 'http://'), or percent-encoding that Addressable normalizes into something URI.parse still rejects.","commonSituations":"User-submitted URL fields pasted from browsers (unencoded unicode/space paths), string interpolation building URLs without escaping, or trimming code that leaves a trailing fragment the parser cannot handle.","solutions":["Normalize/encode the URL before passing it: Addressable::URI.normalize(source).to_s","Validate the param parses as a URI (and scheme is http/https) before assigning it to the uploader","Strip whitespace from user input before download","Rescue CarrierWave::DownloadError and feed the error back as a form validation message"],"exampleFix":"# before\nuploader.download! 'http://example.com/photos/my dog.jpg' # DownloadError: couldn't parse URL\n\n# after\nrequire \"addressable/uri\"\nuploader.download! Addressable::URI.normalize('http://example.com/photos/my dog.jpg').to_s","handlingStrategy":"validation","validationCode":"require 'addressable/uri'\n\ndef safe_remote_url?(source)\n  uri = Addressable::URI.parse(source.to_s.strip)\n  uri.is_a?(Addressable::URI) && %w[http https].include?(uri.normalized_scheme) && !uri.normalized_host.nil?\nrescue Addressable::URI::InvalidURIError, URI::InvalidURIError, ArgumentError\n  false\nend\n\nparams[:avatar_url] = Addressable::URI.normalize(params[:avatar_url].to_s.strip).to_s if safe_remote_url?(params[:avatar_url])","typeGuard":null,"tryCatchPattern":"begin\n  uploader.download!(url)\nrescue CarrierWave::DownloadError => e\n  errors.add(:url, :invalid_url) if e.message =~ /couldn't parse URL/\nend","preventionTips":["Normalize every user-supplied URL through Addressable::URI.normalize before it reaches the uploader","Reject anything whose scheme is not http/https at the form-validation layer","Strip whitespace from pasted URLs; browsers routinely hand you strings with spaces"],"tags":["carrierwave","url","parsing","download","validation"],"backgroundTag":"invalid-url","analyzedSha":"b5f0abe10ecf6500309fc83e0e8969cf57ba690e","analyzedAt":"2026-08-21T18:07:27.715Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}