we-promise/sure · error · Provider::Kraken::ApiError
Malformed Kraken API response
Error message
Malformed Kraken API response
What it means
Raised as Provider::Kraken::ApiError when a successful (2xx) Kraken response body does not parse to a Hash. Kraken's REST API always returns a JSON object {error: [...], result: ...}; a non-Hash parsed body means the payload was an array, scalar, or an empty body (HTTParty's parsed_response can be nil when the body is blank). This guard runs after the status check and before Kraken's in-band error handling.
Source
Thrown at app/models/provider/kraken.rb:127
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"]
end
def classified_error(errors)
message = errors.join(", ")View on GitHub (pinned to e69894adb9)
Solutions
- Reproduce the exact call with curl -i and inspect Content-Length/Content-Type of the response
- Check Kraken status page — truncated/empty 2xx bodies often coincide with incidents
- Retry once; truncated responses are usually transient network artifacts
- If a proxy is in path, bypass it to confirm the raw Kraken response
- Consider treating nil parsed_response (blank body) as retryable distinctly from wrong-shape bodies
Example fix
# before: nil parsed_response (empty body) hits the same opaque guard
parsed = response.parsed_response
raise ApiError, "Malformed Kraken API response" unless parsed.is_a?(Hash)
# after: distinguish empty (retryable) from wrong-shape (fatal)
parsed = response.parsed_response
if parsed.nil?
raise ApiError, "Kraken returned an empty body (HTTP #{response.code})"
end
raise ApiError, "Malformed Kraken API response: #{parsed.class}" unless parsed.is_a?(Hash) Defensive patterns
Strategy: retry
Type guard
# Narrow a parsed Kraken response before use
module KrakenGuard
Envelope = Struct.new(:error, :result)
def self.parse(response)
parsed = response.parsed_response
return nil unless parsed.is_a?(Hash) && parsed.key?("error") && parsed.key?("result")
Envelope.new(Array(parsed["error"]), parsed["result"])
end
end Try / catch
begin result = provider.get_trades_history rescue Provider::Kraken::ApiError => e raise unless e.message == "Malformed Kraken API response" # empty/truncated bodies are usually transient — single retry with backoff sleep 2 retry end
Prevention
- Retry malformed/empty-body responses once with backoff before failing a sync
- Ensure no proxy between the app and api.kraken.com rewrites or truncates JSON bodies
- Stub complete Kraken envelopes in tests ({error: [...], result: ...}) so the guard is exercised deliberately
- Alert when malformed responses persist — that signals gateway or upstream contract problems
When it happens
Trigger: Any Kraken call where the body is empty (connection closed mid-response, 204) or JSON that is not an object — e.g. a proxy serving a bare JSON array/string, or an upstream change in the response envelope. parsed_response returning nil on blank bodies is the most common concrete case.
Common situations: Load balancers or CDNs truncating responses, Kraken maintenance pages returning non-JSON-Object payloads with 2xx, HTTParty version changes in how blank bodies parse, and corporate proxies rewriting bodies.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Malformed Kraken API response: missing error
- Malformed Kraken API response: missing result
- Unexpected response format from search API
- Unexpected response format from EOD API
- Unexpected Frankfurter response shape
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/4944cf50344cacda.
Report an issue: GitHub.