nautechsystems/nautilus_trader · error · anyhow::Error
missing persistence type for order update {}
Error message
missing persistence type for order update {} What it means
Thrown while converting a Betfair Stream API unmatched-order update (`oc` entry) into a NautilusTrader TimeInForce. Betfair carries order persistence in the `pt` (persistenceType) field; a missing `pt` is only tolerated for 'Limit on close' and 'Market on close' order types, which map to TimeInForce::AtTheClose. For any other order type the adapter cannot decide the TIF and bails, failing the parse of that order update.
Source
Thrown at crates/adapters/betfair/src/stream/parse.rs:903
if let Some(lsrc) = uo.lsrc {
report.cancel_reason = Some(lsrc.to_string());
}
Ok(report)
}
fn parse_stream_time_in_force(uo: &UnmatchedOrder) -> anyhow::Result<TimeInForce> {
match uo.pt {
Some(persistence_type) => Ok(TimeInForce::from(persistence_type)),
None if matches!(
uo.ot,
crate::common::enums::StreamingOrderType::LimitOnClose
| crate::common::enums::StreamingOrderType::MarketOnClose
) =>
{
Ok(TimeInForce::AtTheClose)
}
None => anyhow::bail!("missing persistence type for order update {}", uo.id),
}
}
fn stream_order_quantity(uo: &UnmatchedOrder) -> Decimal {
if uo.s > Decimal::ZERO {
return uo.s;
}
let lifecycle_qty = uo.sm.unwrap_or(Decimal::ZERO)
+ uo.sr.unwrap_or(Decimal::ZERO)
+ uo.sc.unwrap_or(Decimal::ZERO)
+ uo.sl.unwrap_or(Decimal::ZERO)
+ uo.sv.unwrap_or(Decimal::ZERO);
if lifecycle_qty > Decimal::ZERO {
return lifecycle_qty;
}
View on GitHub (pinned to a4b06ed870)
Solutions
- Reconnect or re-request the stream - a missing pt on an otherwise normal limit order usually indicates a malformed/lost field in that message
- Dump the raw OCM message and verify `ot`/`pt`; if `pt` is genuinely absent for a plain LIMIT order, capture the payload and report it to the adapter maintainers as an upstream data issue
- If Betfair now legitimately omits pt for a new order type, extend parse_stream_time_in_force in crates/adapters/betfair/src/stream/parse.rs with an explicit mapping for that type
Example fix
// before
let tif = parse_stream_time_in_force(&uo)?;
// after: skip malformed per-order updates instead of failing the stream
let tif = match parse_stream_time_in_force(&uo) {
Ok(tif) => tif,
Err(e) => {
log::warn!("skipping unmatched order {}: {e}", uo.id);
continue;
}
}; Defensive patterns
Strategy: try-catch
Validate before calling
fn has_resolvable_tif(uo: &UnmatchedOrder) -> bool {
uo.pt.is_some()
|| matches!(
uo.ot,
StreamingOrderType::LimitOnClose | StreamingOrderType::MarketOnClose
)
}
// before parsing: if !has_resolvable_tif(&uo) { skip or alert } Type guard
fn is_betfair_order_parseable(uo: &UnmatchedOrder) -> bool {
uo.pt.is_some() || matches!(uo.ot, StreamingOrderType::LimitOnClose | StreamingOrderType::MarketOnClose)
} Try / catch
match parse_stream_time_in_force(&uo) {
Ok(tif) => { /* apply update */ }
Err(e) => log::warn!("skipping order {} with unparseable TIF: {e}", uo.id),
} Prevention
- Log raw OCM messages during integration so missing pt fields can be traced
- Keep Betfair stream replay fixtures current with the live API version
- Warn-and-skip on individual malformed order updates instead of failing the whole stream consumer
When it happens
Trigger: Receiving an OCM stream message whose unmatched order has `pt` null/absent while `ot` is a type other than LimitOnClose or MarketOnClose (e.g. a plain LIMIT order without persistenceType).
Common situations: Malformed or stale Betfair stream messages; replaying captured stream data from an older API-NG version; test fixtures that omit persistenceType; Betfair schema changes on new order types.
Related errors
- failed to resolve positive quantity for stream order update
- BacktestNode state is unavailable when dispose_on_completion
- Market orders on Betfair are only supported with AtTheClose
- failed to resolve positive quantity for current order {} (or
- height must be positive, was {self.height}
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/85943741dd7f01e0.
Report an issue: GitHub.