nautechsystems/nautilus_trader · error · anyhow::Error
missing fee for fill report inst_id={}
Error message
missing fee for fill report inst_id={} What it means
OKX sends the fee on every order fill, and the adapter requires it to build the fill report's commission (Money). This error is thrown when the order message's fee field is absent (None) or whitespace-only, so there is no fee string to parse and the fill report is rejected rather than emitted with a zero/unknown fee.
Source
Thrown at crates/adapters/okx/src/websocket/parse.rs:2151
current_filled
}
} else {
anyhow::bail!(
"Cannot determine fill quantity: fill_sz is empty/zero and acc_fill_sz is empty/zero"
);
}
} else {
anyhow::bail!(
"Cannot determine fill quantity: fill_sz='{}' and acc_fill_sz is None",
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!(View on GitHub (pinned to 18893faf8b)
Solutions
- Filter order updates so only messages with actual fill data (fillSz/accFillSz changed) reach parse_fill_report; canceled orders typically carry no fee.
- Check the raw payload for the given inst_id to confirm fee is genuinely missing from the exchange push.
- If OKX legitimately stopped sending fee on fills for your account tier, update the adapter to fetch fees from the REST fills endpoint or emit the fill without commission.
- Keep the adapter updated to the OKX API version you are targeting.
Example fix
// before: feeding every order update to parse_fill_report
let report = parse_fill_report(&msg, ...)?;
// after: only fill-bearing updates
if msg.fill_sz.is_empty() && msg.acc_fill_sz.map_or(true, |s| s == "0") { return Ok(None); }
let report = parse_fill_report(&msg, ...)?; Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: ensure fee is present before requesting a fill report
fn has_fee(fee: &Option<String>) -> bool {
fee.as_deref().map_or(false, |f| !f.trim().is_empty())
} Type guard
fn fee_present(msg: &OkxOrderMsg) -> Option<&str> {
msg.fee.as_deref().filter(|f| !f.trim().is_empty())
} Try / catch
match parse_fill_report(&msg, ...) {
Ok(r) => emit(r),
Err(e) if e.to_string().contains("missing fee") => {
log::debug!("no fee on update for {} (likely non-fill push); skipping", msg.inst_id);
}
Err(e) => return Err(e),
} Prevention
- Only feed messages with real fill data into parse_fill_report; canceled/unfilled pushes lack fees.
- Confirm your OKX account tier exposes fee fields on the orders channel.
- Track OKX changelog for fee-field changes.
When it happens
Trigger: parse_fill_report receives an OKX 'orders' message whose fee: Option<String> is None or Some(""/whitespace). The error message includes the msg.inst_id of the offending fill.
Common situations: OKX sometimes omits fee on certain order-state pushes (e.g. canceled or newly-created order updates with no fill); using a message variant/channel where fee is not populated; OKX API change removing the field on some fill events.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Failed to parse fee={:?}: {}
- `settle_ccy` or `quote_ccy` is required for EVENTS instrumen
- Missing sz for algo order {}
- Cannot determine spread fill quantity: fill_sz='{}' and acc_
- missing fee for spread fill report sprd_id={}; OKX sprd-orde
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/a2aff8e5de5d000c.
Report an issue: GitHub.