nautechsystems/nautilus_trader · error · anyhow::Error
Failed to encode params: {e}
Error message
Failed to encode params: {e} What it means
sign_spot builds the URL-encoded POST parameter string (nonce plus request params) with serde_urlencoded. This error wraps serialization failure of the params map — e.g. a key/value pair that cannot be percent-encoded into the request body.
Source
Thrown at crates/adapters/kraken/src/common/credential.rs:181
///
/// Note: "nonce + POST data" means the nonce value string is prepended
/// to the URL-encoded POST body, e.g., "1234567890nonce=1234567890¶m=value".
pub fn sign_spot(
&self,
path: &str,
nonce: u64,
params: &HashMap<String, String>,
) -> anyhow::Result<(String, String)> {
let secret = STANDARD
.decode(&self.api_secret)
.map_err(|e| anyhow::anyhow!("Failed to decode API secret: {e}"))?;
let nonce_str = nonce.to_string();
let mut post_data = format!("nonce={nonce_str}");
if !params.is_empty() {
let encoded = serde_urlencoded::to_string(params)
.map_err(|e| anyhow::anyhow!("Failed to encode params: {e}"))?;
post_data.push('&');
post_data.push_str(&encoded);
}
let sha_input = format!("{nonce_str}{post_data}");
let hash = digest::digest(&digest::SHA256, sha_input.as_bytes());
let mut message = path.as_bytes().to_vec();
message.extend_from_slice(hash.as_ref());
let key = hmac::Key::new(hmac::HMAC_SHA512, &secret);
let signature = hmac::sign(&key, &message);
Ok((STANDARD.encode(signature.as_ref()), post_data))
}
/// Sign a JSON request for Kraken Spot API (used for CancelOrderBatch, AddOrderBatch).
///
/// These endpoints use JSON body instead of form-encoded.
/// Signature: HMAC-SHA512(path + SHA256(nonce + json_body))View on GitHub (pinned to 18893faf8b)
Solutions
- Sanitize params to valid UTF-8 strings and strip control characters before signing
- Log/inspect the params map in the wrapped {e} to find the offending entry
- Ensure values come from validated sources (ASCII symbol names, plain numerics)
- Upgrade serde_urlencoded if a serialization bug is suspected
Example fix
// before
params.insert("pair", weird_user_input.to_string());
let sig = creds.sign_spot(path, nonce, ¶ms)?;
// after
let pair: String = weird_user_input.chars().filter(|c| c.is_ascii_graphic()).collect();
params.insert("pair", pair);
let sig = creds.sign_spot(path, nonce, ¶ms)?; Defensive patterns
Strategy: validation
Validate before calling
for (k, v) in ¶ms {
assert!(k.chars().all(|c| c.is_ascii_graphic() || c == ' '));
assert!(v.chars().all(|c| c.is_ascii_graphic() || c == ' '));
} Try / catch
match creds.sign_spot(path, nonce, ¶ms) {
Ok(s) => s,
Err(e) if e.to_string().contains("encode params") => {
eprintln!("unencodable param in request: {e}");
return Err(SignError::BadParams);
}
Err(e) => return Err(e),
} Prevention
- Keep request params ASCII/UTF-8-clean; sanitize values derived from user input
- Validate symbol and parameter strings before building the signed request
- Log the params map (without secrets) when signing fails to locate the bad value
When it happens
Trigger: Calling sign_spot with params containing characters/values serde_urlencoded cannot serialize (non-UTF-8 strings, control characters introduced via env/config) — serde_urlencoded::to_string returns an Err which is wrapped.
Common situations: Non-UTF-8 or control characters in order parameters read from config/environment; params built from user input with invalid encoding; extremely unusual symbol strings.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Failed to decode API secret: {e}
- Kraken Spot does not support the demo environment
- Trailing stop orders are not yet supported on the Kraken WS
- Iceberg (display_qty) orders are not supported on the Kraken
- Unsupported order type for Kraken WS: {order_type:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3617c6f6cd17a063.
Report an issue: GitHub.