we-promise/sure · error · Provider::Binance::AuthenticationError
Unauthorized
Error message
Unauthorized
What it means
Raised by Provider::Binance#handle_response when the Binance REST API returns HTTP 401. The client authenticates by sending the api_key in the X-MBX-APIKEY header (auth_headers). Binance returns 401 when the key is malformed, deleted, or lacks permission for the requested endpoint. The message comes from extract_error_message, which reads parsed["msg"], falling back to "Unauthorized" when the body is unparseable.
Source
Thrown at app/models/provider/binance.rb:182
# HMAC-SHA256 of the query string.
# Accepts either a Hash of params or a pre-built query string.
def sign(params)
query_string = params.is_a?(Hash) ? URI.encode_www_form(params.sort) : params
OpenSSL::HMAC.hexdigest("sha256", api_secret, query_string)
end
def auth_headers
{ "X-MBX-APIKEY" => api_key }
end
def handle_response(response)
parsed = response.parsed_response
case response.code
when 200..299
parsed
when 401
raise AuthenticationError, extract_error_message(parsed) || "Unauthorized"
when 429
raise RateLimitError, "Rate limit exceeded"
else
msg = extract_error_message(parsed) || "API error: #{response.code}"
raise InvalidSymbolError, msg if parsed.is_a?(Hash) && parsed["code"] == -1121
raise ApiError, msg
end
end
def extract_error_message(parsed)
return parsed if parsed.is_a?(String)
return nil unless parsed.is_a?(Hash)
parsed["msg"] || parsed["message"] || parsed["error"]
end
end
View on GitHub (pinned to e69894adb9)
Solutions
- Inspect the stored credential for the Binance provider account and confirm api_key is present and has no whitespace.
- In Binance API Management, confirm the key still exists, is active, and has the required permission (at minimum "Enable Reading").
- If the key has an IP restriction, add the server's current egress IP (or remove the restriction) and retry.
- Regenerate the key on Binance and update the stored credential, then retry the request.
- If the body is empty (message fell back to "Unauthorized"), log response.parsed_response and the raw body to see Binance's exact msg (e.g. "API-key format invalid" vs "API-key format invalid.").
Example fix
# before
provider = Provider::Binance.new(api_key: key, secret_key: secret)
data = provider.get_account # raises AuthenticationError, "Unauthorized"
# after
raise ArgumentError, "Binance api_key is blank" if key.to_s.strip.empty?
provider = Provider::Binance.new(api_key: key.strip, secret_key: secret)
begin
data = provider.get_account
rescue Provider::Binance::AuthenticationError => e
# mark the provider connection as needing re-auth instead of failing the job
provider_account.update!(status: :reauth_required)
Rails.logger.warn("Binance auth failed: #{e.message}")
end Defensive patterns
Strategy: try-catch
Validate before calling
raise ArgumentError, "Binance api_key is blank" if api_key.to_s.strip.empty? raise ArgumentError, "Binance api_key has whitespace" if api_key != api_key.strip
Type guard
def binance_auth_error?(err) err.is_a?(Provider::Binance::AuthenticationError) end
Try / catch
begin result = provider.get_account rescue Provider::Binance::AuthenticationError => e provider_account.update!(status: :reauth_required) DebugLogEntry.capture(category: "binance", level: "error", message: e.message, provider_key: "binance") end
Prevention
- Validate the key is non-blank and stripped before constructing Provider::Binance.
- Store credentials encrypted and re-verify after any key rotation on Binance.
- Confirm IP-restriction whitelist covers the app's egress IP before deploying.
- Never auto-retry AuthenticationError — flag the connection for user re-auth instead.
When it happens
Trigger: Any signed-off request method on Provider::Binance (account, trade, or user-data endpoints) with a blank, mistyped, revoked, or expired API key; a key created without the required "Read" (or trade) permission; a key with an IP access restriction that does not include the server's egress IP; or a key deleted from the Binance account while still stored in the app's provider credentials.
Common situations: Rotating or regenerating keys on Binance without updating the stored credential; copying the key with trailing whitespace/newline; environment drift between staging (working key) and production (stale key); IP-restricted keys behind a container/cloud NAT whose egress IP changed; test suites hitting live Binance with placeholder keys.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/d03d684b50ee14cb.
Report an issue: GitHub.