nautechsystems/nautilus_trader · error
Missing credentials
Error message
Missing credentials
What it means
`sign_spot` signs a private Kraken REST endpoint request, which requires an API key/secret. The client stores its credential in an `Option`, and when it is `None` signing cannot proceed, so this error is returned. It means a private (authenticated) endpoint was called on a client constructed without credentials.
Source
Thrown at crates/adapters/kraken/src/http/spot/client.rs:307
)])
}
fn rate_limit_keys(endpoint: &str) -> Vec<String> {
let normalized = endpoint.split('?').next().unwrap_or(endpoint);
let route = format!("kraken:spot:{normalized}");
vec![KRAKEN_GLOBAL_RATE_KEY.to_string(), route]
}
fn sign_spot(
&self,
path: &str,
nonce: u64,
params: &HashMap<String, String>,
) -> anyhow::Result<(HashMap<String, String>, String)> {
let credential = self
.credential
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Missing credentials"))?;
let (signature, post_data) = credential.sign_spot(path, nonce, params)?;
let mut headers = HashMap::new();
headers.insert("API-Key".to_string(), credential.api_key().to_string());
headers.insert("API-Sign".to_string(), signature);
Ok((headers, post_data))
}
async fn send_request<T: DeserializeOwned>(
&self,
method: Method,
endpoint: &str,
body: Option<Vec<u8>>,
authenticate: bool,
) -> anyhow::Result<KrakenResponse<T>, KrakenHttpError> {
self.send_request_with_body(method, endpoint, RequestBody::Form(body), authenticate)View on GitHub (pinned to 18893faf8b)
Solutions
- Construct the client with valid `api_key` and `api_secret` so `credential` is `Some`.
- Guard call sites: only invoke private endpoints when credentials are configured; check `client.credential.is_some()` first.
- Verify env vars/config that supply the keys are actually loaded before client construction.
Example fix
// before let client = KrakenSpotHttpClient::new(url, "", "", rps, timeout, None)?; client.request_open_positions(...).await?; // Missing credentials // after let client = KrakenSpotHttpClient::new(url, &api_key, &api_secret, rps, timeout, None)?;
Defensive patterns
Strategy: try-catch
Validate before calling
fn ensure_private_ready(client: &KrakenSpotHttpClient) -> Result<(), String> {
if client.credential.is_none() {
Err("private endpoint called without credentials".into())
} else { Ok(()) }
} Type guard
fn has_credential(c: &Option<KrakenCredential>) -> bool { c.is_some() } Try / catch
match client.request_open_positions(params).await {
Ok(reports) => reports,
Err(e) if e.to_string().contains("Missing credentials") => {
return Err(anyhow::anyhow!("configure KRAKEN_API_KEY/KRAKEN_API_SECRET before private calls: {e}"));
}
Err(e) => return Err(e),
} Prevention
- Load API keys from env/config and fail fast at startup if absent
- Route public-only workloads through a credential-free client and private calls through an authenticated one
- Never pass empty strings as key/secret; pass None explicitly so intent is clear
When it happens
Trigger: Calling `send_request_attempt` for a private endpoint (e.g. OpenPositions, Balance) on a client that was created without `api_key`/`api_secret`, or with `credential: None`.
Common situations: Using the client in public-data-only mode and accidentally calling private endpoints; credential loading failed silently upstream; environment variables for keys not set so `None` was passed; refactored constructor defaults dropping credentials.
Related errors
- Authentication failed: {e}
- L3 WebSocket failed to authenticate: {e}
- missing WS auth token
- Binance Spot market data mode SBE requires Ed25519 API crede
- Missing API credentials; set Deribit environment variables
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/cf7328ab431090e8.
Report an issue: GitHub.