we-promise/sure · error · Provider::Kraken::ApiError
Kraken API request failed: #{response.code}
Error message
Kraken API request failed: #{response.code} What it means
Raised as Provider::Kraken::ApiError when the Kraken REST API returns an HTTP status outside 200-299 for a signed private or public request. Kraken normally signals errors in-band with HTTP 200 + an 'error' array, so a non-2xx status indicates a transport/protocol-level problem: 4xx for malformed requests/auth (403 signature, 400 bad payload) or 5xx for Kraken outages. The HTTP code is embedded in the message verbatim.
Source
Thrown at app/models/provider/kraken.rb:123
{
"API-Key" => api_key,
"API-Sign" => sign(path, params)
}
end
def sign(path, params)
encoded_payload = URI.encode_www_form(params)
nonce = params.fetch("nonce").to_s
digest = OpenSSL::Digest::SHA256.digest(nonce + encoded_payload)
hmac = OpenSSL::HMAC.digest("sha512", Base64.decode64(api_secret), path + digest)
Base64.strict_encode64(hmac)
end
def handle_response(response)
parsed = response.parsed_response
unless response.code.between?(200, 299)
raise ApiError, "Kraken API request failed: #{response.code}"
end
unless parsed.is_a?(Hash)
raise ApiError, "Malformed Kraken API response"
end
unless parsed.key?("error")
raise ApiError, "Malformed Kraken API response: missing error"
end
errors = Array(parsed["error"]).reject(&:blank?)
raise classified_error(errors) if errors.any?
unless parsed.key?("result")
raise ApiError, "Malformed Kraken API response: missing result"
end
parsed["result"]View on GitHub (pinned to e69894adb9)
Solutions
- Map the embedded code: 403 → check API key permissions and IP whitelist in Kraken settings; 418/429 → slow down (Kraken rate-limits per key); 5xx → check Kraken status and retry later
- Verify the server clock is NTP-synced — signature validation depends on the nonce/timestamp
- Confirm the API key has the required permissions (Query Funds, Query Open/Closed Orders, etc.) for the endpoint being called
- If IP-whitelisted, add the egress IP of the app server to the key's whitelist
- Honor Retry-After on 429 and add exponential backoff around private_post calls
Example fix
# before: caller retries blindly on any ApiError
rescue Provider::Kraken::ApiError
retry
end
# after: branch on the embedded HTTP code
rescue Provider::Kraken::ApiError => e
code = e.message[/\d{3}/]
raise if code.in?(["403", "400"]) # config errors: fix, don't retry
sleep(e.message.include?("429") ? 5 : 1) # rate limit / transient 5xx
retry
end Defensive patterns
Strategy: try-catch
Validate before calling
# Verify key permissions/clock before long syncs (cheap public call also works) # Kraken private calls need Query Funds + Query Ledger/Orders permissions and NTP-synced clock. # Pre-flight clock check: drift = (Process.clock_gettime(Process::CLOCK_REALTIME) - Time.now.to_f).abs raise "Server clock drift too high for Kraken signing" if drift > 30
Try / catch
begin
result = provider.get_extended_balance
rescue Provider::Kraken::ApiError => e
code = e.message.scan(/\b(\d{3})\b/).last
case code
when "403" then disconnect_kraken("Auth/IP restriction: #{e.message}")
when "418", "429" then reschedule_with_backoff
when nil then raise
else raise if code.start_with?("5").then { |five| !five } # 5xx → retry, else raise
end
end Prevention
- Create Kraken API keys with only the Query permissions the sync needs, and whitelist the server IP
- Keep server clocks NTP-synced — signatures are timestamp-sensitive
- Respect Kraken's tiered call-rate limits with a local throttle (like RateLimitable) to avoid 418/429
- Branch handling on the embedded HTTP code: auth errors are permanent, 429/5xx are transient
When it happens
Trigger: Any private_post/public_get call (BalanceEx, TradesHistory, Ledgers, Assets...) receiving e.g. 403 (bad API key/signature/IP restriction), 418/429 (rate-limited or banned at HTTP layer), 400 (malformed request), or 5xx (Kraken incident). Distinguishable from Kraken's in-band errors, which are classified separately into AuthenticationError/RateLimitError/NonceError/OTPRequiredError.
Common situations: API key without 'Query Funds'/'Query Ledger' permissions enabled, IP whitelist on the Kraken key excluding the server, clock skew breaking signatures, Kraken 5xx during maintenance windows, and Cloudflare-level blocks (403/429) when request volume is too high from one IP.
Related errors
- invalid_import_record
- Unauthorized
- Unauthorized - check your API key and secret
- Rate limit exceeded
- API error: #{response.code}
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/7b982ffec4a31f68.
Report an issue: GitHub.