{"record":{"id":"4a80693f0a715ec9","repo":"nautechsystems/nautilus_trader","slug":"cannot-decode-inverted-price-from-zero-sqrt-price","errorCode":null,"errorMessage":"Cannot decode inverted price from zero sqrt_price_x96","messagePattern":"Cannot decode inverted price from zero sqrt_price_x96","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/tick_map/sqrt_price_math.rs","lineNumber":416,"sourceCode":"\n            if price_square > max_square {\n                U256::ZERO\n            } else {\n                let price_square = U256::checked_from_limbs_slice(price_square.as_limbs())\n                    .ok_or_else(|| {\n                        anyhow::anyhow!(\"Inverted price denominator exceeds U256 range\")\n                    })?;\n                let denominator =\n                    price_square\n                        .checked_mul(decimal_adjustment)\n                        .ok_or_else(|| {\n                            anyhow::anyhow!(\"Inverted price denominator exceeds U256 range\")\n                        })?;\n                FullMath::mul_div(numerator, U256::from(1), denominator)?\n            }\n        } else {\n            let price_square: U512 = sqrt_price.widening_mul(sqrt_price);\n            anyhow::ensure!(\n                !price_square.is_zero(),\n                \"Cannot decode inverted price from zero sqrt_price_x96\"\n            );\n            let numerator = U512::from(divisor_base)\n                .checked_mul(U512::from(decimal_adjustment))\n                .and_then(|value| value.checked_mul(U512::from(fixed_scalar)))\n                .ok_or_else(|| anyhow::anyhow!(\"Inverted price numerator exceeds U512 range\"))?;\n            let quotient = numerator / price_square;\n            U256::checked_from_limbs_slice(quotient.as_limbs())\n                .ok_or_else(|| anyhow::anyhow!(\"Inverted price exceeds U256 range\"))?\n        }\n    } else if decimal_diff >= 0 {\n        FullMath::mul_div_scaled(\n            sqrt_price,\n            sqrt_price,\n            divisor_base,\n            &[fixed_scalar, decimal_adjustment],\n        )?","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/tick_map/sqrt_price_math.rs#L398-L434","documentation":"In the inverted price branch (decimal_diff < 0), the denominator is sqrt_price_x96^2. A zero sqrt_price_x96 would mean division by zero, so the function explicitly rejects it with this error. Uniswap V3 pools can transiently report sqrt_price_x96 == 0 (empty/liquidity-less pool state), which makes an inverted token0/token1 price mathematically undefined.","triggerScenarios":"Calling decode_sqrt_price_x96_to_price_tokens_adjusted with invert=true, token0_decimals < token1_decimals, and sqrt_price_x96 = 0 (as via compute or spot_price).","commonSituations":"Subscribing to a freshly created Uniswap V3 pool before liquidity is added; a pool after all liquidity is removed; decoding on-chain slot0 data for an uninitialized pool.","solutions":["Check sqrt_price_x96 != 0 before calling and skip the pool or default the price to zero.","Handle the error by treating the pool as unpriced (no liquidity) rather than retrying.","If a price is required, wait until the pool has been initialized (slot0.sqrtPriceX96 > 0)."],"exampleFix":"// before\nlet price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price_x96, d0, d1, true)?;\n// after\nif sqrt_price_x96.is_zero() {\n    // unpriced/uninitialized pool\n    return Ok(Price::zero(FIXED_PRECISION));\n}\nlet price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price_x96, d0, d1, true)?;","handlingStrategy":"validation","validationCode":"if sqrt_price_x96.is_zero() { return Ok(Price::zero(FIXED_PRECISION)); }","typeGuard":"fn pool_is_priced(sqrt_price_x96: U160) -> bool { !sqrt_price_x96.is_zero() }","tryCatchPattern":"match decode_sqrt_price_x96_to_price_tokens_adjusted(sp, d0, d1, true) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"zero sqrt_price_x96\") => {\n        tracing::debug!(\"pool unpriced (zero sqrt price)\");\n        Price::zero(FIXED_PRECISION)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always check sqrt_price_x96 != 0 when inverting a price","Treat zero sqrt price as 'pool has no liquidity', not as a fatal error","Initialize pool state from slot0 before decoding prices"],"tags":["rust","defi","uniswap-v3","division-by-zero"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}