diesel-rs/diesel · error

Failed to convert BigDecimal to PgNumeric

Error message

Failed to convert BigDecimal to PgNumeric

What it means

Runtime panic from the deprecated From<BigDecimal> for PgNumeric conversion (kept for backward compatibility; modern ToSql impls use a failable TryFrom-style path instead). Converting an arbitrary BigDecimal into PgNumeric can fail (e.g. digits that do not fit the base-10000 representation), and this legacy infallible API panics with this message in that case. Fix: migrate to the failable conversion path instead of the legacy From impl.

Solutions

  1. Reduce the scale or digit count of the BigDecimal
  2. Normalize the value before conversion
  3. Handle unsupported precision with a custom ToSql implementation
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at diesel/src/pg/types/numeric.rs:92 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of diesel-rs/diesel@6fa6ed01b2 (2026-09-07). Data as JSON: /api/errors/bbbf7ec6c49280e5. Report an issue: GitHub.

Appendix: source

Thrown at diesel/src/pg/types/numeric.rs:92

    #[cfg(all(feature = "postgres_backend", feature = "numeric"))]
    impl TryFrom<PgNumeric> for BigDecimal {
        type Error = Box<dyn Error + Send + Sync>;

        fn try_from(numeric: PgNumeric) -> deserialize::Result<Self> {
            (&numeric).try_into()
        }
    }

    // that should likely be a `TryFrom` impl
    // TODO: diesel 3.0
    // This now mostly exists for backward compatibility
    // Our own `ToSql` impls don't call it anymore in favour of calling
    // the failable inner function instead
    #[cfg(all(feature = "postgres_backend", feature = "numeric"))]
    impl<'a> From<&'a BigDecimal> for PgNumeric {
        fn from(decimal: &'a BigDecimal) -> Self {
            try_convert_decimal_to_pg_numeric(decimal)
                .expect("Failed to convert BigDecimal to PgNumeric")
        }
    }

    // NOTE(clippy): No `std::ops::MulAssign` impl for `BigInt`
    // NOTE(clippy): Clippy suggests to replace the `.take_while(|i| i.is_zero())`
    // with `.take_while(Zero::is_zero)`, but that's a false positive.
    // The closure gets an `&&i16` due to autoderef `<i16 as Zero>::is_zero(&self) -> bool`
    // is called. There is no impl for `&i16` that would work with this closure.
    #[allow(clippy::assign_op_pattern, clippy::redundant_closure)]
    #[cfg(all(feature = "postgres_backend", feature = "numeric"))]
    fn try_convert_decimal_to_pg_numeric(
        decimal: &BigDecimal,
    ) -> Result<PgNumeric, Box<dyn core::error::Error + Send + Sync>> {
        let (mut integer, scale) = decimal.as_bigint_and_exponent();

        // Handling of negative scale
        let scale = if scale < -131064 {
            // that's a guard avoiding the potential expensive calculation below

View on GitHub (pinned to 6fa6ed01b2)