instructure/canvas-lms · error

Error connecting to recaptcha #

Error message

Error connecting to recaptcha #{response}

What it means

In UsersController#validate_recaptcha, when the HTTP response from Google's reCAPTCHA verify endpoint has a non-success status (the else branch), Canvas raises with the raw response. It indicates Canvas could not complete verification, not that the captcha was wrong.

Solutions

  1. Verify outbound HTTPS connectivity from the app server to https://www.google.com/recaptcha/api/siteverify
  2. Check proxy/firewall configuration for the Rails process
  3. Confirm reCAPTCHA site key and secret are valid in account settings
  4. Wrap the call and rescue to return a friendly 'could not verify captcha' response instead of a 500

Example fix

# before
raise "Error connecting to recaptcha #{response}"
# after
Rails.logger.error("reCAPTCHA verification request failed: #{response.code} #{response.body}")
return { errors: ["recaptcha-unreachable"] }
Defensive patterns

Strategy: try-catch

Validate before calling

# ensure outbound reachability before user flows
code = Net::HTTP.get_response(URI('https://www.google.com/recaptcha/api/siteverify')).code rescue nil
ready = code == '200' || code == '405' # endpoint reachable (405 for GET is fine)

Type guard

function recaptchaReachable(resp) {
  return resp != null && typeof resp.code === 'number' && resp.code >= 200 && resp.code < 300;
}

Try / catch

begin
  errors = validate_recaptcha(params)
rescue RuntimeError => e
  if e.message.start_with?('Error connecting to recaptcha')
    flash[:error] = 'Could not verify captcha, please try again'
    redirect_back
  else
    raise
  end
end

Prevention

When it happens

Trigger: create_user with recaptcha enabled while Google's siteverify returns a transport-level failure: network outage, proxy/DNS failure, timeout, 5xx from Google, or missing/invalid recaptcha credentials causing an unexpected response status.

Common situations: Servers without outbound internet access; misconfigured proxy; invalid RECAPTCHA_SITE_KEY/SECRET; Google siteverify outage.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/b02ade5622dbce0a. Report an issue: GitHub.

Appendix: source

Thrown at app/controllers/users_controller.rb:3534

  def validate_recaptcha(recaptcha_response)
    # if there is no recaptcha key or recaptcha is disabled, don't do anything
    return nil unless recaptcha_enabled?
    # Authenticated API requests do not require a captcha
    return nil unless @access_token.nil?

    response = CanvasHttp.post("https://www.google.com/recaptcha/api/siteverify", form_data: {
                                 secret: Rails.application.credentials.dig(:recaptcha_keys, :server_key),
                                 response: recaptcha_response
                               })

    if response && response.code == "200"
      parsed = JSON.parse(response.body)
      return { errors: parsed["error-codes"] } unless parsed["success"]
      return { errors: ["invalid-hostname"] } unless parsed["hostname"] == request.host

      nil
    else
      raise "Error connecting to recaptcha #{response}"
    end
  end

  def locale_dates_for(course, current_course)
    return { start_at_locale: nil, end_at_locale: nil } unless current_course&.locale.present?

    I18n.with_locale(current_course.locale) do
      {
        start_at_locale: datetime_string(course.start_at, :verbose, nil, shorten_midnight: true),
        end_at_locale: datetime_string(course.conclude_at, :verbose, nil, shorten_midnight: true)
      }
    end
  end

  def fetch_courses_with_grades(observed_user = nil)
    target_user = observed_user || @current_user

    # Use menu_courses to get filtered course list (handles favorites, invited enrollments, etc.)

View on GitHub (pinned to 1c9f0bb801)