nautechsystems/nautilus_trader · error
Invalid funding_interval, cannot be negative
Error message
Invalid funding_interval, cannot be negative
What it means
parse_funding_rate_msg computes the funding interval as next_funding_time - funding_time from the OKX funding-rate websocket message. `duration_since` returns None when the next funding time is earlier than the current funding time, so the adapter rejects the message rather than emitting a FundingRateUpdate with a negative interval. This guards the downstream u16 minutes field and any interval-based scheduling logic.
Source
Thrown at crates/adapters/okx/src/common/parse.rs:568
/// Returns an error if the `funding_rate` field fails
/// to parse into a Decimal value or `next_funding_time` fails to parse into a positive, in bounds interval.
pub fn parse_funding_rate_msg(
msg: &OKXFundingRateMsg,
instrument_id: InstrumentId,
ts_init: UnixNanos,
) -> anyhow::Result<FundingRateUpdate> {
let funding_rate = msg
.funding_rate
.as_str()
.parse::<Decimal>()
.map_err(|e| anyhow::anyhow!("Invalid funding_rate value: {e}"))?;
let funding_time = parse_millisecond_timestamp(msg.funding_time);
let next_funding_time = parse_millisecond_timestamp(msg.next_funding_time);
let funding_interval_nanos =
next_funding_time
.duration_since(&funding_time)
.ok_or(anyhow::anyhow!(
"Invalid funding_interval, cannot be negative"
))?;
let funding_interval = u16::try_from(funding_interval_nanos.as_mins())
.context("funding_interval out of bounds")?;
let ts_event = parse_millisecond_timestamp(msg.ts);
Ok(FundingRateUpdate::new(
instrument_id,
funding_rate,
Some(funding_interval),
Some(funding_time),
ts_event,
ts_init,
))
}
/// Parses a [`OKXFundingRateHistory`] into a [`FundingRateUpdate`].
///View on GitHub (pinned to 18893faf8b)
Solutions
- Log the raw msg.funding_time and msg.next_funding_time values to confirm the negative delta before treating it as an adapter bug
- Skip or ignore the offending message and wait for the next funding rate update instead of failing the whole stream
- Validate that next_funding_time > funding_time (and both non-zero) in your ingestion layer before calling parse_funding_rate_msg
- If OKX changed the field semantics, pin/upgrade the nautilus OKX adapter version matching the current API docs
Example fix
// before
let next = parse_millisecond_timestamp(msg.next_funding_time);
let update = parse_funding_rate_msg(&msg, instrument_id, ts_init)?;
// after
let funding_time = parse_millisecond_timestamp(msg.funding_time);
let next = parse_millisecond_timestamp(msg.next_funding_time);
if next == 0 || next <= funding_time {
log::warn!("Skipping funding rate msg with invalid times: funding_time={funding_time}, next_funding_time={next}");
return Ok(None);
}
let update = parse_funding_rate_msg(&msg, instrument_id, ts_init)?; Defensive patterns
Strategy: validation
Validate before calling
let funding_time = parse_millisecond_timestamp(msg.funding_time);
let next = parse_millisecond_timestamp(msg.next_funding_time);
if next == 0 || funding_time == 0 || next <= funding_time {
// skip or normalize this message before calling parse_funding_rate_msg
} Type guard
fn has_valid_funding_times(msg: &OKXFundingRateMsg) -> bool {
let t = parse_millisecond_timestamp(msg.funding_time);
let nt = parse_millisecond_timestamp(msg.next_funding_time);
t > 0 && nt > t
} Try / catch
match parse_funding_rate_msg(&msg, instrument_id, ts_init) {
Ok(update) => handle(update),
Err(e) if e.to_string().contains("cannot be negative") => log::warn!("skipping bad funding msg: {e}"),
Err(e) => return Err(e),
} Prevention
- Validate timestamp pairs before parsing
- Skip rather than fail on individual bad websocket messages
- Watch OKX release notes for funding-time field changes
- Pin and regularly update the OKX adapter version
When it happens
Trigger: An OKX funding rate update arrives where next_funding_time < funding_time (after parse_millisecond_timestamp coercion), typically because the exchange sent a zero/stale/placeholder timestamp pair or timestamps crossed a partial-fill boundary (e.g. next_funding_time=0 coerced to a default earlier than funding_time).
Common situations: Exchange clock or message ordering anomalies on the OKX websocket; snapshots where next_funding_time is empty/zero and parse_millisecond_timestamp falls back to a value before funding_time; replaying out-of-order historical funding messages; temporary OKX API schema changes.
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
- Invalid funding_rate value: {e}
- Negative nanosecond timestamp from: {timestamp}
- Unknown position currency '{pos_ccy}' for instrument {instru
- Invalid timeframe for `BarSpecification`, was {timeframe}
- invalid funding_rate_timestamp
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/8ec83b08310fdad5.
Report an issue: GitHub.