{"record":{"id":"2eac9031314b88ec","repo":"docusealco/docuseal","slug":"error-loading-uri","errorCode":null,"errorMessage":"Error loading: #{uri}","messagePattern":"Error loading: #(.+?)","errorType":"exception","errorClass":"DownloadUtils::UnableToDownload","httpStatus":422,"severity":"error","filePath":"lib/download_utils.rb","lineNumber":49,"sourceCode":"    'ip6-allrouters'\n  ].freeze\n\n  UnableToDownload = Class.new(StandardError)\n\n  module_function\n\n  def call(url, validate: Docuseal.multitenant?)\n    uri = begin\n      URI(url)\n    rescue URI::Error\n      Addressable::URI.parse(url).normalize\n    end\n\n    validate_uri!(uri) if validate\n\n    resp = conn(validate:).get(uri)\n\n    raise UnableToDownload, \"Error loading: #{uri}\" if resp.status >= 400\n\n    resp\n  end\n\n  def validate_uri!(uri)\n    raise UnableToDownload, \"Error loading: #{uri}. Only HTTPS is allowed.\" if uri.scheme != 'https' ||\n                                                                               [443, nil].exclude?(uri.port)\n    raise UnableToDownload, \"Error loading: #{uri}. Can't download from localhost.\" if uri.host.in?(LOCALHOSTS)\n  end\n\n  def conn(validate: Docuseal.multitenant?)\n    Faraday.new do |faraday|\n      faraday.response :follow_redirects, callback: lambda { |_, new_env|\n        validate_uri!(new_env[:url]) if validate\n      }\n    end\n  end\nend","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/docusealco/docuseal/blob/004a22c1c88109c7ba0b567df011a8cb13894001/lib/download_utils.rb#L31-L67","documentation":"DownloadUtils.call fetches a remote URL (e.g. attach_url files, webhook-fetched documents) and raises UnableToDownload with 'Error loading: <uri>' when the remote answers HTTP >= 400. It is strictly an HTTP-level failure - the URL was valid enough to request, but the server refused or errored. Scheme/host validation (HTTPS-only, no localhost) happens separately in validate_uri! with its own messages.","triggerScenarios":"Passing a file URL that 404s or 403s: expired presigned S3 links, auth-gated assets, hotlink-protected CDNs; provider 5xx during incidents; URLs that redirect to an error page.","commonSituations":"Presigned links expiring before download; moving a bucket or file without updating stored URLs; providers requiring headers the plain Faraday GET does not send.","solutions":["From the app host, run a HEAD/GET against the URL to see the exact status the downloader gets.","Fix the URL: refresh the signature, correct permissions, or use a durable location.","If the provider requires auth, serve the file through an authenticated endpoint you control.","For recurring rot, store stable URLs and resolve them to signed links at download time."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# pre-flight the URL before handing it to DownloadUtils\nresp = Faraday.head(url)\nraise UnableToDownload, \"Error loading: #{url}\" if resp.status >= 400","typeGuard":null,"tryCatchPattern":"begin\n  DownloadUtils.call(url)\nrescue UnableToDownload => e\n  Rails.logger.warn(e.message)\n  notify_owner_of_failed_attachment(e.message)\nend","preventionTips":["Use long-lived presigned URLs or resolve signatures lazily","Monitor download failures per host","Pre-flight HEAD checks for user-supplied URLs"],"tags":["download","http-error","faraday","file-url"],"backgroundTag":"http-error-response","analyzedSha":"004a22c1c88109c7ba0b567df011a8cb13894001","analyzedAt":"2026-08-21T13:38:23.343Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}