{"record":{"id":"641bace2753ca59f","repo":"n0-computer/iroh","slug":"invalidbucketconfig","errorCode":"InvalidBucketConfig","errorMessage":"invalid bucket config","messagePattern":"invalid bucket config","errorType":"validation","errorClass":"InvalidBucketConfig","httpStatus":null,"severity":"error","filePath":"iroh-relay/src/server/streams.rs","lineNumber":405,"sourceCode":"}\n\nimpl Bucket {\n    /// Creates a new bucket starting full at `max` tokens, refilled at\n    /// `bytes_per_second` over `refill_period` intervals.\n    ///\n    /// # Errors\n    ///\n    /// Returns [`InvalidBucketConfig`] when `max`, `bytes_per_second`, or\n    /// `refill_period` are non-positive, or when the configuration would refill\n    /// less than one token per period.\n    pub fn new(\n        max: i64,\n        bytes_per_second: i64,\n        refill_period: time::Duration,\n    ) -> Result<Self, InvalidBucketConfig> {\n        // milliseconds is the tokio timer resolution\n        let refill = bytes_per_second.saturating_mul(refill_period.as_millis() as i64) / 1000;\n        ensure!(\n            max > 0 && bytes_per_second > 0 && refill_period.as_millis() as u32 > 0 && refill > 0,\n            InvalidBucketConfig {\n                max,\n                bytes_per_second,\n                refill_period\n            }\n        );\n        Ok(Self {\n            fill: max,\n            max,\n            last_fill: time::Instant::now(),\n            refill_period,\n            refill,\n        })\n    }\n\n    fn from_config(cfg: Option<ClientRateLimit>) -> Result<Option<Self>, InvalidBucketConfig> {\n        match cfg {","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/n0-computer/iroh/blob/2b4de030ce5e0133f272871a76f0c685c63f552a/iroh-relay/src/server/streams.rs#L387-L423","documentation":"A rate-limit token bucket was constructed with parameters that can never work: non-positive capacity, non-positive bytes_per_second, a zero-millisecond refill period, or a computed refill amount that rounds down to zero. The constructor `new` validates these up front and returns InvalidBucketConfig.","triggerScenarios":"Calling RateBucket::new with max <= 0, bytes_per_second <= 0, refill_period < 1ms, or a combination where bytes_per_second * refill_period_ms / 1000 saturates to 0 (e.g. very small rate with a very short refill period).","commonSituations":"Relay rate-limit config loaded from files/env as 0 or negative defaults, unit conversions losing precision (bytes/sec to ms buckets), users setting refill_period below 1ms because tokio's timer is millisecond-resolution.","solutions":["Set max and bytes_per_second to positive values and refill_period to at least 1ms.","Ensure bytes_per_second * refill_period_ms >= 1000 so the refill amount is > 0 (e.g. 1 KiB/s needs >= ~977ms period).","Validate rate-limit values when loading configuration and reject 0/negatives early.","If a very small rate is intended, lengthen refill_period rather than shrinking it."],"exampleFix":"// before\nRateBucket::new(now, 0, 1024, Duration::from_millis(0))?; // invalid\n// after\nRateBucket::new(now, 1024 * 1024, 1024, Duration::from_secs(1))?;","handlingStrategy":"validation","validationCode":"fn valid_bucket_config(max: i64, bps: i64, period: std::time::Duration) -> bool {\n    max > 0 && bps > 0 && period.as_millis() > 0 && (bps.saturating_mul(period.as_millis() as i64) / 1000) > 0\n}","typeGuard":"fn checked_bucket(max: i64, bps: i64, period: std::time::Duration) -> Option<(i64, i64, std::time::Duration)> {\n    valid_bucket_config(max, bps, period).then_some((max, bps, period))\n}","tryCatchPattern":"match RateBucket::new(now, max, bps, period) {\n    Err(e) => { log::error!(\"invalid rate-limit config: {:?}\", e); return Err(ConfigError::RateLimit(e)); }\n    Ok(b) => b,\n}","preventionTips":["Validate rate-limit values when loading config; reject 0 and negatives.","Remember tokio timers have 1ms resolution; keep refill_period >= 1ms.","Ensure bps * period_ms >= 1000 so refill > 0.","Add property tests for boundary configs."],"tags":["rate-limit","configuration","validation","relay"],"backgroundTag":"invalid-config-value","analyzedSha":"2b4de030ce5e0133f272871a76f0c685c63f552a","analyzedAt":"2026-09-08T04:26:47.755Z","contentChangedAt":"2026-09-08T04:26:47.755Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}