arsduo/koala · error · Koala::Facebook::BadFacebookResponse

generate_client_code received an error: empty response body

Error message

generate_client_code received an error: empty response body

What it means

Koala::Facebook::BadFacebookResponse (a subclass of APIError) is raised by OAuth#generate_client_code when its GET /oauth/client_code call (client_id, client_secret, redirect_uri, access_token, always over SSL through fetch_token_string) returns HTTP 200 with a completely empty body. Facebook uses an empty 200 body instead of a JSON error for several failure modes on this endpoint, so Koala cannot extract an error code and surfaces the raw condition; the exception carries http_status 200 and an empty response_body.

Source

Thrown at lib/koala/oauth.rb:135

      # access token from Facebook. After which the clients can use that access token to make
      # requests to Facebook without having to use the server token, yet the server access token
      # remains valid.
      # See https://developers.facebook.com/docs/facebook-login/access-tokens/#long-via-code
      #
      # @param access_token a user's long lived (server) access token
      #
      # @raise Koala::Facebook::ServerError if Facebook returns a server error (status >= 500)
      # @raise Koala::Facebook::OAuthTokenRequestError if Facebook returns an error response (status >= 400)
      # @raise Koala::Facebook::BadFacebookResponse if Facebook returns a blank response
      # @raise Koala::KoalaError if response does not contain 'code' hash key
      #
      # @return a string of the generated 'code'
      def generate_client_code(access_token)
        response = fetch_token_string({:redirect_uri => @oauth_callback_url, :access_token => access_token}, false, 'client_code')

        # Facebook returns an empty body in certain error conditions
        if response == ''
          raise BadFacebookResponse.new(200, '', 'generate_client_code received an error: empty response body')
        else
          result = JSON.parse(response)
        end

        result.has_key?('code') ? result['code'] : raise(Koala::KoalaError.new("Facebook returned a valid response without the expected 'code' in the body (response = #{response})"))
      end

      # access tokens

      # Fetches an access token, token expiration, and other info from Facebook.
      # Useful when you've received an OAuth code using the server-side authentication process.
      # @see url_for_oauth_code
      #
      # @note (see #url_for_oauth_code)
      #
      # @param code (see #url_for_access_token)
      # @param options any additional parameters to send to Facebook when redeeming the token
      #

View on GitHub (pinned to 47d052063e)

Solutions

  1. Verify the access token is a valid long-lived user token: exchange it first with @oauth.exchange_access_token(token) and feed the returned token to generate_client_code.
  2. Make the callback URL passed as the third argument to Koala::Facebook::OAuth.new exactly match a Valid OAuth Redirect URI in the Facebook app dashboard (scheme, host, path, trailing slash).
  3. Confirm the app_id and app_secret belong to the same app that issued the token; check for dev and prod app mixups.
  4. Retry once after a short delay to rule out a transient Facebook-side empty response.
  5. Enable Koala::Utils.logger or Faraday logging to capture the exact /oauth/client_code request and response.

Example fix

// before
@oauth = Koala::Facebook::OAuth.new(APP_ID, APP_SECRET)
code = @oauth.generate_client_code(token)

// after
@oauth = Koala::Facebook::OAuth.new(APP_ID, APP_SECRET, "https://example.com/auth/callback")
long_lived = @oauth.exchange_access_token(token)
begin
  code = @oauth.generate_client_code(long_lived)
rescue Koala::Facebook::BadFacebookResponse => e
  Rails.logger.warn("client_code failed: #{e.message}")
  code = nil
end
Defensive patterns

Strategy: try-catch

Validate before calling

raise ArgumentError, "oauth callback URL must be configured" unless @oauth.oauth_callback_url.to_s.start_with?("https://")
raise ArgumentError, "token does not look long-lived" if token.to_s.length < 100

Type guard

def long_lived_server_token?(token)
  token.is_a?(String) && token.length > 100 # long-lived tokens are roughly 200 chars
end

Try / catch

begin
  code = @oauth.generate_client_code(token)
rescue Koala::Facebook::BadFacebookResponse => e
  # HTTP 200 with empty body: suspect token validity or redirect_uri mismatch
  Rails.logger.warn("client_code rejected: #{e.message}")
  code = nil
end

Prevention

When it happens

Trigger: Calling @oauth.generate_client_code(access_token) where the token is expired or invalid, is a short-lived client token rather than the long-lived server token, or was issued for a different app; or where the redirect_uri Koala sends (taken from @oauth_callback_url, the third OAuth.new argument) does not exactly match a Valid OAuth Redirect URI configured in the Facebook app dashboard. Facebook accepts the request with 200, returns a zero-length body, and line 134 converts that into this exception.

Common situations: Dev and production credential mixups (wrong secret or callback URL per environment); forgetting to extend the short-lived token with exchange_access_token before requesting a client code; trailing-slash or http-vs-https differences between the configured callback and the app dashboard; occasional transient Facebook-side empty responses.

Related errors


AI-assisted analysis of arsduo/koala@47d052063e (2026-08-23). Data as JSON: /api/errors/f6a107a3ac7da926. Report an issue: GitHub.