nautechsystems/nautilus_trader · error · anyhow::Error
Invalid fee denom: {e}
Error message
Invalid fee denom: {e} What it means
The fee Coin's denom string (the on-chain token denomination, e.g. "adydx") is parsed into cosmrs's Denom type, which validates denomination rules. If self.fee_denom is not a valid Cosmos SDK coin denomination, parse fails and this error is returned.
Source
Thrown at crates/adapters/dydx/src/grpc/builder.rs:108
// Gas price for dYdX (typically 0.025 adydx per gas)
let gas_price = Decimal::new(25, 3); // 0.025
let amount = (gas_price * gas_limit).ceil();
let gas_limit_u64 = gas_limit
.to_u64()
.ok_or_else(|| anyhow::anyhow!("Failed converting gas limit to u64"))?;
let amount_u128 = amount
.to_u128()
.ok_or_else(|| anyhow::anyhow!("Failed converting gas cost to u128"))?;
Ok(Fee::from_amount_and_gas(
Coin {
amount: amount_u128,
denom: self
.fee_denom
.parse()
.map_err(|e| anyhow::anyhow!("Invalid fee denom: {e}"))?,
},
gas_limit_u64,
))
}
/// Get default fee (zero fee).
fn default_fee() -> Fee {
Fee {
amount: vec![],
gas_limit: 0,
payer: None,
granter: None,
}
}
/// Build a transaction for given messages.
///
/// When `authenticator_ids` is provided, the transaction will include a `TxExtension`View on GitHub (pinned to 18893faf8b)
Solutions
- Set fee_denom to the correct lowercase native denom, "adydx", in the client config.
- Check for empty/missing config: ensure the fee denom config field is populated (this will otherwise parse as an invalid empty denom).
- Match the denom exactly to what the dYdX chain expects for the target network (mainnet vs testnet).
- Validate the denom against Cosmos denom rules (lowercase alnum, may contain '/' and ':', 3-128 chars) before constructing the builder.
Example fix
// before // fee_denom: "ADYDX".to_string(), // uppercase invalid // after fee_denom: "adydx".to_string(),
Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_denom(d: &str) -> bool {
!d.is_empty()
&& d.len() >= 3
&& d.len() <= 128
&& d.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '/' || c == ':')
}
assert!(is_valid_denom(&fee_denom)); Try / catch
let fee = client.calculate_fee(instrument_id, gas_limit)
.map_err(|e| {
if e.to_string().contains("Invalid fee denom") {
// fix fee_denom config to "adydx"
}
e
})?; Prevention
- Default fee_denom to "adydx" (lowercase) for dYdX mainnet
- Fail fast at config load if fee_denom is empty or uppercase
- Confirm the denom matches the target network (mainnet vs testnet)
When it happens
Trigger: Calling calculate_fee when the builder's fee_denom field contains an invalid denom: empty string, uppercase letters, invalid characters, or a too-long string per Cosmos denom rules.
Common situations: Configuring the adapter with a typo'd fee denom (e.g. "ADYDX" instead of "adydx"); an empty or missing config field defaulting to an invalid denom; a network whose native denom differs from the configured one (mainnet adydx vs testnet variants).
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- request_rate_per_second must be greater than zero
- order_request_rate_per_second must be greater than zero
- heartbeat_secs must be positive when set
- heartbeat_timeout_secs must cover at least two server heartb
- `router_addresses` must contain at least one router address
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e92504f45fda9921.
Report an issue: GitHub.