databendlabs/databend · error

i256 overflow

Error message

i256 overflow

What it means

The Neg implementation for the 256-bit signed decimal type i256 uses checked_neg and panics on 'i256 overflow'. Negating i256::MIN (the only value whose negation is not representable in two's complement 256-bit) overflows and triggers this panic. All other i256 values negate fine.

Solutions

  1. Check for i256::MIN before negating and return an overflow error (decimal overflow / value out of range).
  2. Use a checked/returning-Result arithmetic path for user-driven expressions instead of the panicking Neg operator.
  3. Constrain input decimals so values cannot reach i256::MIN in expressions that negate.

Example fix

// before
let y = -x;
// after
let y = if x == i256::MIN { return Err(ErrorCode::Overflow("decimal negation")); } else { -x };
Defensive patterns

Strategy: validation

Validate before calling

if x == i256::MIN {
    return Err(ErrorCode::Overflow("negating i256::MIN overflows"));
}
let y = -x;

Type guard

fn negatable(x: i256) -> bool { x != i256::MIN }

Prevention

When it happens

Trigger: Computing -x where x == i256::MIN (e.g. unary minus on the most negative decimal value, or arithmetic like 0 - i256::MIN routed through Neg).

Common situations: Decimal arithmetic on extreme user values: a literal or computed decimal equal to the minimum 256-bit value passed through unary minus, ABS-style transformations, or negation inside aggregate/window functions.

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


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/a42278ddf2391f57. Report an issue: GitHub.

Appendix: source

Thrown at src/query/expression/src/types/decimal.rs:2920

impl std::fmt::Debug for i256 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:?}", self.0)
    }
}

impl std::fmt::Display for i256 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Neg for i256 {
    type Output = Self;

    #[inline]
    fn neg(self) -> Self::Output {
        Self(self.0.checked_neg().expect("i256 overflow"))
    }
}

impl AddAssign for i256 {
    fn add_assign(&mut self, rhs: Self) {
        self.0 += rhs.0;
    }
}

impl SubAssign for i256 {
    fn sub_assign(&mut self, rhs: Self) {
        self.0 -= rhs.0;
    }
}

impl MulAssign for i256 {
    fn mul_assign(&mut self, rhs: Self) {
        self.0 *= rhs.0;

View on GitHub (pinned to 288d84d76e)