{"record":{"id":"f1ab44731de2d5f5","repo":"databendlabs/databend","slug":"sample-size-must-be-greater-than-zero","errorCode":null,"errorMessage":"sample size must be greater than zero","messagePattern":"sample size must be greater than zero","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/expression/src/sampler/fixed_size_sampler.rs","lineNumber":37,"sourceCode":"\n/// A fixed-capacity owning reservoir sampler using Vitter's Algorithm L.\n///\n/// Like Spark's `reservoirSampleAndCount`, the reservoir owns at most `k` values and also tracks\n/// the input cardinality. Algorithm L replaces Spark's per-row Algorithm R decision with an exact\n/// skip calculation, avoiding work for rows that cannot enter the reservoir. Input block boundaries\n/// do not affect the resulting sample.\npub struct FixedSizeSampler<T, R: Rng> {\n    samples: Vec<T>,\n    k: usize,\n    rows_seen: usize,\n    // Zero-based global stream index selected next by Algorithm L.\n    next_sample: Option<usize>,\n    core: AlgoL<R>,\n}\n\nimpl<T, R: Rng> FixedSizeSampler<T, R> {\n    pub fn new(k: usize, rng: R) -> Self {\n        let k = NonZeroUsize::new(k).expect(\"sample size must be greater than zero\");\n        Self {\n            samples: Vec::with_capacity(k.get()),\n            k: k.get(),\n            rows_seen: 0,\n            next_sample: None,\n            core: AlgoL::new(k, rng),\n        }\n    }\n\n    /// Consider one logical block while preserving the same result as one continuous row stream.\n    ///\n    /// `value_at` is evaluated only for rows entering the reservoir: every row during the initial\n    /// fill, then only the rows selected by Algorithm L.\n    pub fn add_block<F>(&mut self, rows: usize, mut value_at: F)\n    where F: FnMut(usize) -> T {\n        let start = self.rows_seen;\n        let end = start.checked_add(rows).expect(\"sample row count overflow\");\n        let mut row = 0;","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/expression/src/sampler/fixed_size_sampler.rs#L19-L55","documentation":"FixedSizeSampler::new builds a reservoir sampler with capacity k, and internally represents k as a NonZeroUsize. This panic fires when a caller constructs a FixedSizeSampler with k == 0, which is meaningless for reservoir sampling (the sampler would never retain rows). The library treats a zero sample size as a programming error rather than a runtime condition.","triggerScenarios":"Calling FixedSizeSampler::new(0, rng), or passing a k value computed from configuration/other code that evaluates to 0 (e.g. an unset or empty sampling setting).","commonSituations":"A sampling size config option left at 0 or defaulted incorrectly; a query setting like SAMPLE_SIZE=0; an off-by-one computation of the requested sample size before constructing the sampler.","solutions":["Ensure the sample size passed to FixedSizeSampler::new is at least 1 before constructing the sampler.","Validate the user-facing setting (e.g. sample size option) and return a proper error like ErrorCode::IllegalScalar for 0 instead of reaching the sampler.","If 0 is legitimate, skip sampling entirely and use an empty result rather than constructing a sampler."],"exampleFix":"// before\nlet sampler = FixedSizeSampler::new(sample_size, rng);\n// after\nassert!(sample_size > 0, \"sample_size setting must be positive\");\nlet sampler = FixedSizeSampler::new(sample_size.max(1), rng);","handlingStrategy":"validation","validationCode":"if sample_size == 0 {\n    return Err(ErrorCode::IllegalScalar(\"sample size must be greater than zero\"));\n}\nlet sampler = FixedSizeSampler::new(sample_size, rng);","typeGuard":"fn valid_sample_size(k: usize) -> bool { k > 0 }","tryCatchPattern":null,"preventionTips":["Validate sampling-related settings at query compile time, not inside the sampler.","Treat 0 as 'no sampling needed' and short-circuit before constructing a sampler."],"tags":["panic","reservoir-sampling","invalid-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}