nautechsystems/nautilus_trader · error
OpenPositions: failed to build Quantity for {inst_id}: {e:?}
Error message
OpenPositions: failed to build Quantity for {inst_id}: {e:?} What it means
After resolving the instrument, the adapter converts the position volume into a Nautilus `Quantity` using the instrument's `size_precision`. `Quantity::from_decimal_dp` fails when the parsed value cannot be represented at that precision, and the adapter wraps the debug error in this anyhow message. It means Kraken-reported volume is incompatible with the instrument's size precision.
Source
Thrown at crates/adapters/kraken/src/http/spot/client.rs:2446
}
let mut reports = Vec::new();
for (_, (signed_qty, inst_id)) in agg {
let instrument = self
.get_cached_instrument(&inst_id.symbol.inner())
.ok_or_else(|| InstrumentLookupError::not_found(inst_id))?;
let side = if signed_qty.is_sign_positive() && !signed_qty.is_zero() {
PositionSide::Long
} else if signed_qty.is_sign_negative() && !signed_qty.is_zero() {
PositionSide::Short
} else {
PositionSide::Flat
};
let quantity = Quantity::from_decimal_dp(signed_qty.abs(), instrument.size_precision())
.map_err(|e| {
anyhow::anyhow!("OpenPositions: failed to build Quantity for {inst_id}: {e:?}")
})?;
let report = PositionStatusReport::new(
account_id, inst_id, side, quantity, ts_init, ts_init, None, None, None,
);
reports.push(report);
}
// If a specific instrument was requested but no open position exists for it, emit
// a FLAT report so the engine can reconcile a previously-open position to closed.
// (Kraken omits fully-closed positions from OpenPositions entirely.)
// Only emit for instruments known to this spot client; a missing cache entry means
// the target belongs to a different product type (e.g. futures) and must not receive
// a spurious FLAT from the spot reconciliation path.
if let Some(target_id) = instrument_id {
let already_reported = reports.iter().any(|r| r.instrument_id == target_id);
if !already_reported
&& let Some(instrument) = self.get_cached_instrument(&target_id.symbol.inner())View on GitHub (pinned to 18893faf8b)
Solutions
- Update the instrument definition so `size_precision` matches Kraken's `lot_decimals` for the pair.
- Inspect the inner `{e:?}` for the exact precision/parse problem and the offending `vol` value.
- Re-fetch instruments to refresh precision after Kraken announces pair changes.
- If the value is genuinely over-precise, round to the instrument precision at the strategy layer before it reaches the venue volume, or report the venue data as unexpected.
Defensive patterns
Strategy: validation
Validate before calling
fn validate_volume(vol: &str, size_precision: u8) -> Result<(), String> {
let d = rust_decimal::Decimal::from_str_exact(vol)
.map_err(|e| format!("bad vol {vol}: {e}?"))?;
let scale = d.scale();
if scale as u8 > size_precision {
Err(format!("vol {vol} has {} dp, instrument allows {}
", scale, size_precision))
} else { Ok(()) }
} Try / catch
match client.request_open_positions().await {
Ok(r) => r,
Err(e) if e.to_string().contains("failed to build Quantity") => {
log::warn!("venue volume incompatible with instrument precision: {e}");
Vec::new() // skip bad position, alert operator
}
Err(e) => return Err(e),
} Prevention
- Keep instrument size_precision synced with Kraken lot_decimals
- Refresh instrument definitions when Kraken changes pair specs
- Reconcile positions incrementally so a single bad value doesn't block the whole report
When it happens
Trigger: OpenPositions parsing where `pos.vol` (parsed via `Decimal::from_str_exact`) has more decimal places than `instrument.size_precision()`, is negative in an unexpected way, or otherwise cannot be rounded/represented as a Quantity at the instrument precision.
Common situations: Stale or wrong instrument definition whose size_precision does not match the venue's current precision; Kraken changes pair volume precision; corrupted/unexpected `vol` string in the API response (e.g. scientific notation the exact parser rejects).
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Order quantity {quantity} is not exactly representable in {d
- quantity size={} cannot be represented with precision={}
- Failed to get open positions: {error_msg}
- value rounded to zero for quantity
- AX {field} scale must not exceed 26 for exact percent conver
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9af263f49f5aa602.
Report an issue: GitHub.