{"record":{"id":"c4dfa74a7fe5dad6","repo":"instructure/canvas-lms","slug":"assets-url-for-app-must-be-a-valid-url","errorCode":null,"errorMessage":"assets_url for '#{app}' must be a valid URL","messagePattern":"assets_url for '#(.+?)' must be a valid URL","errorType":"validation","errorClass":"ArgumentError","httpStatus":400,"severity":"error","filePath":"app/controllers/microfrontends_release_tag_override_controller.rb","lineNumber":78,"sourceCode":"\n    unless override_params.respond_to?(:each)\n      raise ArgumentError, \"override parameter must be a hash\"\n    end\n\n    override_params.each do |app, assets_url|\n      next if assets_url.blank?\n\n      unless SUPPORTED_APPS.include?(app)\n        raise ArgumentError, \"app '#{app}' must be one of: #{SUPPORTED_APPS.join(\", \")}\"\n      end\n\n      begin\n        uri = URI.parse(assets_url)\n        unless ALLOWED_HOSTS.include?(uri.host)\n          raise ArgumentError, \"assets_url host for '#{app}' must be one of: #{ALLOWED_HOSTS.join(\", \")}\"\n        end\n      rescue URI::InvalidURIError\n        raise ArgumentError, \"assets_url for '#{app}' must be a valid URL\"\n      end\n    end\n  end\nend\n","sourceCodeStart":60,"sourceCodeEnd":83,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/controllers/microfrontends_release_tag_override_controller.rb#L60-L83","documentation":"Raised by validate_params! when URI.parse(assets_url) raises URI::InvalidURIError, meaning the value for an app is not a parseable URL (missing scheme, illegal characters, malformed). It is re-raised as ArgumentError with a per-app message.","triggerScenarios":"Passing a bare hostname without scheme, an empty-ish string with spaces or control characters, or a truncated URL in params[:override][app]; JSON values that got mangled (e.g. missing https://).","commonSituations":"Hand-edited config/scripts dropping the https:// prefix; shell quoting stripping characters; trailing newlines from environment variables copied into the payload.","solutions":["Send a fully qualified absolute URL including scheme (https://host/path)","Trim whitespace/newlines from the value before sending","URI-escape any special characters in the path","Validate with URI.parse (or equivalent) client-side before submitting"],"exampleFix":"// before\n{ override: { 'k5': 'cdn.instructure.com/k5' } }\n// after\n{ override: { 'k5': 'https://cdn.instructure.com/k5' } }","handlingStrategy":"validation","validationCode":"let u; try { u = new URL(assets_url); } catch { throw new Error(`${app} assets_url must be absolute https URL`); }","typeGuard":"const isAbsoluteUrl = (s) => { try { const u = new URL(s); return !!u.protocol && !!u.hostname; } catch { return false; } };","tryCatchPattern":"begin\n  validate_params!\nrescue ArgumentError => e\n  render json: { error: e.message }, status: :bad_request\nend","preventionTips":["Always include the https:// scheme","Trim whitespace/newlines from values","Pre-validate with URI.parse/new URL before submitting"],"tags":["ruby","url-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}