embassy-rs/embassy · error

overflow when multiplying duration by scalar

Error message

overflow when multiplying duration by scalar

What it means

`Duration * u32` in embassy-time is implemented via `checked_mul`; if the scaled tick count overflows the duration representation, `.expect("overflow when multiplying duration by scalar")` panics. Std's `Duration` behaves the same way (documented panic on overflow).

Solutions

  1. Use checked arithmetic: `d.checked_mul(n).unwrap_or(Duration::MAX)`
  2. Cap the base duration before scaling (start backoff from a small value and cap the max delay)
  3. Reduce precision first (convert to seconds before multiplying) when sub-microsecond precision isn't needed

Example fix

// before
let delay = base * backoff_factor; // panics when large
// after
let delay = base.checked_mul(backoff_factor).unwrap_or(Duration::from_secs(3600));
Defensive patterns

Strategy: validation

Validate before calling

fn safe_mul(d: embassy_time::Duration, n: u32) -> embassy_time::Duration {
    d.checked_mul(n).unwrap_or(embassy_time::Duration::MAX)
}

Try / catch

// Panic is not catchable in embedded; use checked mul:
let scaled = d.checked_mul(n).ok_or(CalcError::Overflow)?;

Prevention

When it happens

Trigger: `duration * factor` where `duration` is large and `factor` pushes the product past `Duration::MAX` (e.g. `Duration::from_secs(u32::MAX) * u32::MAX` style scaling, or multiplying microsecond-precision values by big multipliers).

Common situations: Exponential backoff multipliers applied to already-large timeouts; converting units (multiplying by 1_000_000) on large second values; retry loops where the delay keeps multiplying.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/efe317766bd1f3de. Report an issue: GitHub.

Appendix: source

Thrown at embassy-time/src/duration.rs:265

    /// ## Panics
    ///
    /// Panics if the computed duration overflows.
    fn sub_assign(&mut self, rhs: Duration) {
        *self = *self - rhs;
    }
}

impl Mul<u32> for Duration {
    type Output = Duration;

    /// Computes `Duration * u32`. [Read more](Mul)
    ///
    /// ## Panics
    ///
    /// Panics if the computed duration overflows.
    fn mul(self, rhs: u32) -> Duration {
        self.checked_mul(rhs)
            .expect("overflow when multiplying duration by scalar")
    }
}

impl Mul<Duration> for u32 {
    type Output = Duration;

    /// Computes `u32 * Duration`. [Read more](Mul)
    ///
    /// ## Panics
    ///
    /// Panics if the computed duration overflows.
    fn mul(self, rhs: Duration) -> Duration {
        rhs * self
    }
}

impl MulAssign<u32> for Duration {
    /// Computes `Duration *= u32`. [Read more](MulAssign)

View on GitHub (pinned to 463a07b963)