nautechsystems/nautilus_trader · error · anyhow::Error
AX maintenance_margin_pct must be positive, was {maintenance
Error message
AX maintenance_margin_pct must be positive, was {maintenance_margin_pct} What it means
parse_margin_rates requires maintenance_margin_pct to be strictly greater than zero before percent-to-rate conversion. A zero or negative maintenance percent — usually an unset field — aborts parsing of the instrument, even when the initial margin is valid.
Source
Thrown at crates/adapters/architect_ax/src/http/parse.rs:388
Some(taker_fee),
None,
Some(info),
ts_event,
ts_init,
);
Ok(InstrumentAny::PerpetualContract(instrument))
}
fn parse_margin_rates(
initial_margin_pct: Decimal,
maintenance_margin_pct: Decimal,
) -> anyhow::Result<(Decimal, Decimal)> {
anyhow::ensure!(
initial_margin_pct > Decimal::ZERO,
"AX initial_margin_pct must be positive, was {initial_margin_pct}"
);
anyhow::ensure!(
maintenance_margin_pct > Decimal::ZERO,
"AX maintenance_margin_pct must be positive, was {maintenance_margin_pct}"
);
anyhow::ensure!(
maintenance_margin_pct <= initial_margin_pct,
"AX maintenance_margin_pct {maintenance_margin_pct} exceeds initial_margin_pct {initial_margin_pct}"
);
Ok((
margin_percent_to_rate(initial_margin_pct, "initial_margin_pct")?,
margin_percent_to_rate(maintenance_margin_pct, "maintenance_margin_pct")?,
))
}
fn margin_percent_to_rate(value: Decimal, field: &str) -> anyhow::Result<Decimal> {
let normalized = value.normalize();
let scale = normalized.scale();
anyhow::ensure!(View on GitHub (pinned to a4b06ed870)
Solutions
- Set a positive maintenance_margin_pct for the symbol in AX venue config
- Confirm the API field mapping for your version so the value is not silently defaulted to 0
- If the venue truly has no separate maintenance tier, set it equal to (not exceeding) the initial margin percent
- Reload instruments after the config fix
Example fix
// before (AX contract metadata) "maintenance_margin_pct": "0" // after "maintenance_margin_pct": "0.5"
Defensive patterns
Strategy: try-catch
Validate before calling
// Vet margin fields before definitions reach the parser
fn maintenance_margin_ok(v: Decimal) -> bool { v > Decimal::ZERO }
if !maintenance_margin_ok(definition.maintenance_margin_pct) {
anyhow::bail!("symbol {} has non-positive maintenance_margin_pct {}}", definition.symbol, definition.maintenance_margin_pct);
} Try / catch
match parse_instrument(&definition, ts_event, ts_init) {
Ok(instrument) => Ok(instrument),
Err(e) if e.to_string().contains("maintenance_margin_pct must be positive") => {
log::error!("symbol {} margin config incomplete (maintenance_margin_pct <= 0)", definition.symbol);
Err(e)
}
Err(e) => Err(e),
} Prevention
- Require both margin percents (not just initial) in venue config validation
- When a venue has no separate maintenance tier, configure it equal to the initial margin
- Re-run instrument loads after every margin config change and assert parse success
When it happens
Trigger: An instrument definition arrives with maintenance_margin_pct 0 (unconfigured listing) or negative, while initial_margin_pct may be fine; the load of that symbol fails inside parse_margin_rates.
Common situations: Margin config partially filled — initial set but maintenance left at default 0; API field renames causing zero-default deserialization; venues that do not distinguish maintenance margin (values omitted).
Related errors
- AX initial_margin_pct must be positive, was {initial_margin_
- AX instrument product must be non-empty without surrounding
- AX minimum_order_size must be a positive whole number, was {
- AX maintenance_margin_pct {maintenance_margin_pct} exceeds i
- AX dated contract {} has different quote and settlement curr
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/191375d81e8a0b74.
Report an issue: GitHub.