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
- 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.
- 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).
- Confirm the app_id and app_secret belong to the same app that issued the token; check for dev and prod app mixups.
- Retry once after a short delay to rule out a transient Facebook-side empty response.
- 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
- Extend tokens to long-lived with exchange_access_token before generating a client code; only server tokens qualify
- Keep one configured callback URL used for both url_for_oauth_code and generate_client_code so redirect_uri always matches
- Separate dev and prod app credentials per environment so tokens are never redeemed against the wrong app
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
- OAuthTokenRequestError.new(response.status, response.body)
- Invalid (incomplete) signature data
- Unsupported algorithm #{envelope['algorithm']}
- Invalid signature
- Koala::Utils.logger.warn("Signed cookie didn't contain Faceb
AI-assisted analysis of arsduo/koala@47d052063e (2026-08-23).
Data as JSON: /api/errors/f6a107a3ac7da926.
Report an issue: GitHub.