{"record":{"id":"af732acdbb68c609","repo":"transact-rs/sqlx","slug":"provided-bigdecimal-could-not-convert-to-i64-over","errorCode":null,"errorMessage":"Provided BigDecimal could not convert to i64: overflow.","messagePattern":"Provided BigDecimal could not convert to i64: overflow\\.","errorType":"exception","errorClass":"io::Error (InvalidData)","httpStatus":null,"severity":"error","filePath":"sqlx-postgres/src/types/money.rs","lineNumber":136,"sourceCode":"\n    /// Convert a [`BigDecimal`](bigdecimal::BigDecimal) value into money using the correct precision\n    /// defined in the PostgreSQL settings. The default precision is two.\n    #[cfg(feature = \"bigdecimal\")]\n    pub fn from_bigdecimal(\n        decimal: bigdecimal::BigDecimal,\n        locale_frac_digits: u32,\n    ) -> Result<Self, BoxDynError> {\n        use bigdecimal::ToPrimitive;\n\n        let multiplier = bigdecimal::BigDecimal::new(\n            num_bigint::BigInt::from(10i128.pow(locale_frac_digits)),\n            0,\n        );\n\n        let cents = decimal * multiplier;\n\n        let money = cents.to_i64().ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"Provided BigDecimal could not convert to i64: overflow.\",\n            )\n        })?;\n\n        Ok(Self(money))\n    }\n}\n\nimpl Type<Postgres> for PgMoney {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::MONEY\n    }\n}\n\nimpl PgHasArrayType for PgMoney {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::MONEY_ARRAY","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/transact-rs/sqlx/blob/03af8bcc5711a1935580a54bea249c219a0c217d/sqlx-postgres/src/types/money.rs#L118-L154","documentation":"PgMoney::from_bigdecimal converts a BigDecimal amount into cents by multiplying by a multiplier and fitting the result into an i64. If the scaled value exceeds i64 range, the to_i64() conversion returns None and sqlx raises this InvalidData error instead of silently truncating. It protects against storing a money value that cannot be represented in Postgres MONEY (8-byte cents).","triggerScenarios":"Calling PgMoney::from_bigdecimal with a BigDecimal whose absolute value, after multiplication by the currency multiplier, overflows i64 (roughly > 92 quadrillion cents or extremely small scales with huge multipliers).","commonSituations":"Loading user-supplied or aggregated amounts (sums of many transactions) without bounds; passing a BigDecimal with absurd exponent/scale parsed from untrusted input; currency conversion multiplying values past i64 range.","solutions":["Validate/clamp the BigDecimal range before conversion (check magnitude against i64::MAX / multiplier)","Store large amounts as NUMERIC instead of MONEY and map to BigDecimal in sqlx","Normalize the decimal's scale first (with_scale) so the multiplier and result stay in range","Reject or log amounts above your domain's real-world maximum at input validation time"],"exampleFix":"// before\nlet money = PgMoney::from_bigdecimal(amount, 2)?;\n// after: bound-check first\nlet cents = &amount * 100;\nif cents > BigDecimal::from(i64::MAX) || cents < BigDecimal::from(i64::MIN) {\n    return Err(anyhow!(\"amount {} out of MONEY range\", amount));\n}\nlet money = PgMoney::from_bigdecimal(amount, 2)?;","handlingStrategy":"validation","validationCode":"use bigdecimal::BigDecimal;\nfn fits_money(amount: &BigDecimal, multiplier: i64) -> bool {\n    let cents = amount * BigDecimal::from(multiplier);\n    cents <= BigDecimal::from(i64::MAX) && cents >= BigDecimal::from(i64::MIN)\n}","typeGuard":"fn to_i64_cents(d: &bigdecimal::BigDecimal) -> Option<i64> {\n    use bigdecimal::ToPrimitive;\n    d.to_i64()\n}","tryCatchPattern":"match PgMoney::from_bigdecimal(amount.clone(), 2) {\n    Ok(money) => store(money),\n    Err(e) if e.to_string().contains(\"could not convert to i64\") => {\n        // store as NUMERIC instead of MONEY\n        store_numeric(&amount)?;\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Bound-check monetary inputs at the application boundary (max transaction amount)","Store amounts as NUMERIC rather than MONEY when values can grow via aggregation","Unit-test conversions with boundary values (i64::MAX/100, i64::MIN/100)"],"tags":["postgres","money","overflow","bigdecimal"],"backgroundTag":"integer-conversion-overflow","analyzedSha":"03af8bcc5711a1935580a54bea249c219a0c217d","analyzedAt":"2026-09-03T15:01:28.752Z","contentChangedAt":"2026-09-03T15:01:28.752Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}