nautechsystems/nautilus_trader · error · anyhow::Error

Failed to parse fee={:?}: {}

Error message

Failed to parse fee={:?}: {}

What it means

The adapter parses the fee string into a Money amount (parse_fee negates OKX's negative-sign convention so charges become positive). This error is thrown when parse_fee fails even though the raw Decimal conversion succeeded — typically the fee currency could not be resolved or the value is out of the allowed range for Money.

Source

Thrown at crates/adapters/okx/src/websocket/parse.rs:2161

            msg.fill_sz
        );
    };

    let fee_str = msg
        .fee
        .as_deref()
        .filter(|fee| !fee.trim().is_empty())
        .ok_or_else(|| anyhow::anyhow!("missing fee for fill report inst_id={}", msg.inst_id))?;
    let fee_dec = Decimal::from_str(fee_str)
        .map_err(|e| anyhow::anyhow!("Failed to parse fee '{fee_str}': {e}"))?;

    let fee_currency = parse_fee_currency(msg.fee_ccy.as_str(), fee_dec, || {
        format!("fill report for inst_id={}", msg.inst_id)
    });

    // OKX sends fees as negative numbers (e.g., "-2.5" for a $2.5 charge), parse_fee negates to positive
    let total_fee = parse_fee(Some(fee_str), fee_currency)
        .map_err(|e| anyhow::anyhow!("Failed to parse fee={:?}: {}", msg.fee, e))?;

    // OKX sends cumulative fees, so we subtract the previous total to get this fill's fee
    let commission = if let Some(previous_fee) = previous_fee {
        if total_fee.currency == previous_fee.currency {
            let incremental = total_fee - previous_fee;

            if incremental < Money::zero(fee_currency) {
                log::debug!(
                    "Negative incremental fee detected - likely a maker rebate or fee refund: order_id={}, total_fee={}, previous_fee={}, incremental={}",
                    msg.ord_id.as_str(),
                    total_fee,
                    previous_fee,
                    incremental,
                );
            }

            // Skip corruption check when previous is negative (rebate), as transitions from
            // rebate to charge legitimately have incremental > total (e.g., -1 → +2 gives +3)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Register the fee currency (fee_ccy) in the local currency/currency-registry used by parse_fee_currency and parse_fee.
  2. Log msg.fee and msg.fee_ccy for the failing fill and compare against the currencies the adapter knows.
  3. Update the adapter's currency mapping if OKX introduced new fee currencies.
  4. Report upstream if the fee value is valid but Money construction still fails (precision bug in the adapter).
Defensive patterns

Strategy: type-guard

Validate before calling

// Rust: ensure fee_ccy is a known currency before processing fills
fn fee_currency_known(ccy: &str, registry: &CurrencyRegistry) -> bool {
    registry.contains(ccy)
}

Type guard

fn known_fee_ccy<'a>(msg: &'a OkxOrderMsg, registry: &CurrencyRegistry) -> Option<&'a str> {
    registry.contains(&msg.fee_ccy).then_some(msg.fee_ccy.as_str())
}

Try / catch

match parse_fill_report(&msg, ...) {
    Ok(r) => emit(r),
    Err(e) if e.to_string().contains("Failed to parse fee=") => {
        register_currency(&msg.fee_ccy); // then retry once
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: parse_fill_report: parse_fee(Some(fee_str), fee_currency) returns Err — e.g. a precision/currency issue in the fee_currency derived from fee_ccy, or a value that cannot be represented as Money at the currency's precision.

Common situations: fee_ccy from OKX is a currency unknown to the local currency registry (new listing, unusual quote ccy); fee magnitude beyond Money precision; mismatch between the decimal precision of the fee and the currency's precision.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/9e0fdb63c392511b. Report an issue: GitHub.