nautechsystems/nautilus_trader · error
Both `api_key` and `api_secret` must be provided together
Error message
Both `api_key` and `api_secret` must be provided together
What it means
BitmexWebSocketClient::new requires WebSocket credentials to be complete or absent: api_key and api_secret must both be Some (authenticated) or both None (public). Passing exactly one of them is ambiguous and rejected at construction time.
Source
Thrown at crates/adapters/bitmex/src/websocket/client.rs:121
///
/// # Errors
///
/// Returns an error if only one of `api_key` or `api_secret` is provided (both or neither required).
#[expect(clippy::too_many_arguments)]
pub fn new(
url: Option<String>,
api_key: Option<String>,
api_secret: Option<String>,
account_id: Option<AccountId>,
heartbeat: u64,
auth_timeout_secs: Option<u64>,
transport_backend: TransportBackend,
proxy_url: Option<String>,
) -> anyhow::Result<Self> {
let credential = match (api_key, api_secret) {
(Some(key), Some(secret)) => Some(Credential::new(key, secret)),
(None, None) => None,
_ => anyhow::bail!("Both `api_key` and `api_secret` must be provided together"),
};
let account_id = account_id.unwrap_or(AccountId::from("BITMEX-master"));
let initial_mode = AtomicU8::new(ConnectionMode::Closed.as_u8());
let connection_mode = Arc::new(ArcSwap::from_pointee(initial_mode));
// Placeholder channel until connect() creates the real one
let (cmd_tx, _cmd_rx) = tokio::sync::mpsc::unbounded_channel::<HandlerCommand>();
Ok(Self {
url: url.unwrap_or(BITMEX_WS_URL.to_string()),
credential,
heartbeat: Some(heartbeat),
auth_timeout_secs: auth_timeout_secs.unwrap_or(AUTHENTICATION_TIMEOUT_SECS),
account_id,
auth_tracker: AuthTracker::new(),
signal: Arc::new(AtomicBool::new(false)),View on GitHub (pinned to 18893faf8b)
Solutions
- Provide both api_key and api_secret together, or pass None for both to run in public (unauthenticated) mode
- Check your config source/env vars so both BITMEX_API_KEY and BITMEX_API_SECRET are set to non-empty values
- If unauthenticated market data is all you need, explicitly pass None for both instead of leaving a half-filled config
- Fail fast at startup: validate the credential pair in your config loader before constructing the client
Example fix
// before
let client = BitmexWebSocketClient::new(
Some(config.api_key), // api_secret missing in config
None,
account_id,
transport_backend,
proxy_url,
)?;
// after
let (key, secret) = match (config.api_key.as_deref(), config.api_secret.as_deref()) {
(Some(k), Some(s)) if !k.is_empty() && !s.is_empty() => (Some(k.to_string()), Some(s.to_string())),
(None, None) => (None, None),
_ => anyhow::bail!("api_key and api_secret must both be set (or both omitted)"),
};
let client = BitmexWebSocketClient::new(key, secret, account_id, transport_backend, proxy_url)?; Defensive patterns
Strategy: validation
Validate before calling
fn validate_ws_creds(api_key: &Option<String>, api_secret: &Option<String>) -> Result<(), String> {
match (api_key, api_secret) {
(Some(k), Some(s)) if !k.is_empty() && !s.is_empty() => Ok(()),
(None, None) => Ok(()),
_ => Err("api_key and api_secret must be provided together".into()),
}
} Type guard
fn complete_creds(k: &Option<String>, s: &Option<String>) -> Option<(&str, &str)> {
match (k, s) {
(Some(k), Some(s)) if !k.is_empty() && !s.is_empty() => Some((k, s)),
_ => None,
}
} Try / catch
let client = BitmexWebSocketClient::new(api_key, api_secret, account_id, backend, proxy)
.map_err(|e| {
if e.to_string().contains("api_key") && e.to_string().contains("api_secret") {
ConfigError::new("credential pair incomplete: provide both or neither")
} else { e.into() }
})?; Prevention
- Load both BITMEX_API_KEY and BITMEX_API_SECRET together in your config struct as a single Credential type
- Fail at config-load time if exactly one credential is set
- Pass explicit None for both when running public market-data-only clients
- Check secret-manager deployments inject both keys, not just the key id
When it happens
Trigger: Constructing BitmexWebSocketClient::new(...) with api_key set but api_secret None, or vice versa — typically a config struct where only one credential was populated.
Common situations: Environment providing BITMEX_API_KEY but not BITMEX_API_SECRET (or a secret stripped by a deployment secret manager); copy-pasted config where the secret field was left empty; wiring the same credential tuple to multiple adapters where one field got dropped.
Related errors
- {secret_var} is required when {key_var} is provided
- {key_var} is required when {secret_var} is provided
- Redis config error: username supplied without password. Eith
- API credentials not configured
- Missing environment variable: {key_env}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3fc3dd81f00ed3d1.
Report an issue: GitHub.