flippercloud/flipper · error · Flipper::Adapters::Http::Error
Failed with status: #{response.code}
Error message
Failed with status: #{response.code} What it means
The Http adapter talks to a Flipper API endpoint (Flipper Cloud at https://www.flippercloud.io/adapter, or a self-hosted flipper-api). get() issues GET /features/<key> and only accepts 200 (parse gates) or 404 (feature unknown, return defaults); every other status raises Flipper::Adapters::Http::Error. The message shows the status code plus any JSON `message`/`more_info` from the API body, and the full Net::HTTP response is attached as error.response for inspection.
Source
Thrown at lib/flipper/adapters/http.rb:40
open_timeout: options[:open_timeout],
write_timeout: options[:write_timeout],
max_retries: options[:max_retries],
debug_output: options[:debug_output])
@last_get_all_etag = nil
@last_get_all_result = nil
@last_get_all_response = nil
@get_all_mutex = Mutex.new
end
def get(feature)
response = @client.get("/features/#{path_escape(feature.key)}")
if response.is_a?(Net::HTTPOK)
parsed_response = Typecast.from_json(response.body)
result_for_feature(feature, parsed_response.fetch('gates'))
elsif response.is_a?(Net::HTTPNotFound)
default_config
else
raise Error, response
end
end
def get_multi(features)
response = @client.get("/features?#{query_for_features(features)}")
raise Error, response unless response.is_a?(Net::HTTPOK)
parsed_response = Typecast.from_json(response.body)
parsed_features = parsed_response.fetch('features')
gates_by_key = parsed_features.each_with_object({}) do |parsed_feature, hash|
hash[parsed_feature['key']] = parsed_feature['gates']
hash
end
result = {}
features.each do |feature|
result[feature.key] = result_for_feature(feature, gates_by_key[feature.key])
endView on GitHub (pinned to 1f86de3ec9)
Solutions
- Check error.response.code and error.response.body (or set debug_output: $stderr on the adapter / FLIPPER_CLOUD_DEBUG_OUTPUT_STDOUT=1) to see the exact status and API message.
- For 401/403: confirm the token header — Flipper Cloud needs FLIPPER_CLOUD_TOKEN set and the URL left at the default /adapter endpoint; rotate the token in Cloud settings if it is stale.
- For wrong-endpoint responses: verify the url option actually reaches a Flipper API (self-hosted: https://app.example.com/flipper/api or wherever flipper-api is mounted), not the UI.
- For 429/5xx transient failures: serve reads from a local cache (Cloud does this via local_adapter + DualWrite/Poll), or wrap the Http adapter with Flipper::Adapters::Failsafe/Failover plus Memoizable so checks degrade instead of raising.
- Set explicit read/open/write timeouts on the adapter so hung endpoints fail fast rather than piling up.
Example fix
# before
adapter = Flipper::Adapters::Http.new(url: "http://localhost:9999/") # UI, not an API
Flipper.new(adapter)[:search].enabled? # => Failed with status: 404/500
# after
http = Flipper::Adapters::Http.new(
url: ENV.fetch("FLIPPER_CLOUD_URL", "https://www.flippercloud.io/adapter"),
headers: { "flipper-cloud-token" => ENV.fetch("FLIPPER_CLOUD_TOKEN") },
read_timeout: 5, open_timeout: 2
)
flipper = Flipper.new(Flipper::Adapters::Failsafe.new(http, errors: [Flipper::Adapters::Http::Error])) Defensive patterns
Strategy: fallback
Validate before calling
require "net/http" uri = URI.join(flipper_url, "/features/nonexistent_probe") response = Net::HTTP.get_response(uri) # 200/401/403 tells you auth is the problem before wiring Flipper; a 404/HTML body tells you the URL is wrong puts response.code
Try / catch
begin Flipper[:search].enabled? rescue Flipper::Adapters::Http::Error => e case e.response when Net::HTTPUnauthorized, Net::HTTPForbidden then raise # config bug, fail loudly else false # transient upstream failure: fail closed end end
Prevention
- Wrap the Http adapter in Flipper::Adapters::Failsafe or Failover plus Memoizable so reads degrade instead of raising.
- Serve reads from a local adapter (Cloud's DualWrite + Poll design) and reserve HTTP for writes/sync.
- Set read/open/write timeouts and keep tokens in env vars validated at boot.
- Turn on debug_output when wiring the adapter to catch wrong-endpoint mistakes immediately.
When it happens
Trigger: GET /features/<key> returning 401/403 (bad or missing flipper-cloud-token header / basic auth), 429 (Cloud rate limiting), 5xx (Cloud outage or self-hosted API error), or any non-200/404 from a URL that is not actually a Flipper API. Raised from feature checks (get, get_multi, get_all, features) when reads go over HTTP.
Common situations: Missing/rotated FLIPPER_CLOUD_TOKEN so every request 401s; URL pointed at the wrong place (the UI on port 9999 instead of the mounted /api path, or a typo'd host returning HTML error pages); expired/invalid Cloud environment token; a reverse proxy or WAF intercepting with 403/502; a Cloud incident returning 5xx.
Related errors
- Actor limit of #{@limit} exceeded for feature #{feature.key}
- Group #{name.inspect} has already been registered
- Your database needs to be migrated to use the latest Flipper
- #{data_type} is not supported by this adapter
- #{gate} is not supported by this adapter yet
AI-assisted analysis of flippercloud/flipper@1f86de3ec9 (2026-08-23).
Data as JSON: /api/errors/a32a6e28b4f3284a.
Report an issue: GitHub.