we-promise/sure · error · LunchflowError
unauthorized
unauthorized
Error message
Invalid API key
What it means
HTTP 401 branch of Provider::Lunchflow#handle_response (app/models/provider/lunchflow.rb:128-129). Thrown as LunchflowError(:unauthorized) with message 'Invalid API key' whenever Lunchflow answers any endpoint with 401, meaning the x-api-key header sent by auth_headers (line 115) is missing, malformed, revoked, or simply wrong. Note: in get_accounts/get_account_transactions/get_account_balance/get_account_holdings this error is subsequently re-wrapped by the method-level catch-all into :request_failed (message becomes 'Exception during GET request: Invalid API key').
Source
Thrown at app/models/provider/lunchflow.rb:129
private
def auth_headers
{
"x-api-key" => api_key,
"Content-Type" => "application/json",
"Accept" => "application/json"
}
end
def handle_response(response)
case response.code
when 200
JSON.parse(response.body, symbolize_names: true)
when 400
Rails.logger.error "Lunch Flow API: Bad request - #{response.body}"
raise LunchflowError.new("Bad request to Lunch Flow API: #{response.body}", :bad_request)
when 401
raise LunchflowError.new("Invalid API key", :unauthorized)
when 403
raise LunchflowError.new("Access forbidden - check your API key permissions", :access_forbidden)
when 404
raise LunchflowError.new("Resource not found", :not_found)
when 429
raise LunchflowError.new("Rate limit exceeded. Please try again later.", :rate_limited)
else
Rails.logger.error "Lunch Flow API: Unexpected response - Code: #{response.code}, Body: #{response.body}"
raise LunchflowError.new("Failed to fetch data: #{response.code} #{response.message} - #{response.body}", :fetch_failed)
end
end
class LunchflowError < StandardError
attr_reader :error_type
def initialize(message, error_type = :unknown)
super(message)
@error_type = error_typeView on GitHub (pinned to e69894adb9)
Solutions
- Re-copy the API key from the Lunchflow dashboard into the provider settings, stripping whitespace/newlines.
- Verify the key out-of-band: curl -H 'x-api-key: <key>' https://lunchflow.app/api/v1/accounts — 200 confirms the key, 401 confirms the key is bad.
- Confirm the key belongs to the same account/workspace the base_url targets.
- Handle :unauthorized in the caller by marking the connection as needing re-auth rather than retrying.
Example fix
// before client = Provider::Lunchflow.new(api_key) client.get_accounts // after raise ArgumentError, 'Lunchflow API key is missing' if api_key.blank? client = Provider::Lunchflow.new(api_key.strip) client.get_accounts
Defensive patterns
Strategy: validation
Validate before calling
raise ArgumentError, 'API key missing' if api_key.to_s.strip.empty? client = Provider::Lunchflow.new(api_key.to_s.strip)
Type guard
def unauthorized?(e)
e.is_a?(Provider::Lunchflow::LunchflowError) &&
(e.error_type == :unauthorized || e.message.include?('Invalid API key'))
end Try / catch
begin client.get_accounts rescue Provider::Lunchflow::LunchflowError => e raise unless unauthorized?(e) connection.update!(status: 'reauth_required') notify_user_to_reenter_lunchflow_key(connection) end
Prevention
- Strip whitespace/newlines when storing provider keys.
- Verify new keys with one cheap get_accounts call at save time.
- Never auto-retry 401s — prompt re-authentication instead.
When it happens
Trigger: Any client call where the stored API key fails authentication: key with leading/trailing whitespace or a newline from copy-paste, a key revoked or rotated in the Lunchflow dashboard, a key from a different Lunchflow workspace/environment, or a Mercury 'secret-token:' accidentally saved in the Lunchflow settings.
Common situations: User re-issued keys in the provider dashboard but did not update them in the app; secrets copied with quotes or padding; staging key used against production base_url (or vice versa); CI running without the provider credentials seeded.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- unauthorized
- Unauthorized
- Unauthorized - check your API key and secret
- Trading 212 authentication failed (#{response.code}). Check
- unauthorized
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/c98bcc19a6201b9c.
Report an issue: GitHub.