{"record":{"id":"3075c63394908c8e","repo":"astrid-runtime/astrid","slug":"throughput-sample-count-must-be-non-zero","errorCode":null,"errorMessage":"throughput sample count must be non-zero","messagePattern":"throughput sample count must be non-zero","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-chunker-evidence/src/throughput.rs","lineNumber":51,"sourceCode":"    let chunk_only = samples(candidate, &fixture, false, DEFAULT_SAMPLES)?;\n    let chunk_and_blake3 = samples(candidate, &fixture, true, DEFAULT_SAMPLES)?;\n    Ok(ThroughputResult {\n        candidate: candidate.name.clone(),\n        fixture_bytes: u64::try_from(fixture.len())?,\n        samples: u64::try_from(DEFAULT_SAMPLES)?,\n        chunk_only,\n        chunk_and_blake3,\n    })\n}\n\nfn samples(\n    candidate: &Candidate,\n    fixture: &[u8],\n    hash_chunks: bool,\n    count: usize,\n) -> Result<Timing> {\n    if count == 0 {\n        bail!(\"throughput sample count must be non-zero\");\n    }\n    let mut durations = Vec::with_capacity(count);\n    for _ in 0..count {\n        let started = Instant::now();\n        let mut guard = [0_u8; 32];\n        candidate.visit_records(Cursor::new(fixture), |bytes, logical_chunks| {\n            if hash_chunks {\n                fold_digest(&mut guard, blake3::hash(bytes).as_bytes());\n            } else {\n                guard[0] ^= bytes.first().copied().unwrap_or_default();\n                guard[1] ^= u8::try_from(logical_chunks & 0xff)?;\n            }\n            Ok(())\n        })?;\n        black_box(guard);\n        durations.push(started.elapsed());\n    }\n    durations.sort_unstable();","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-chunker-evidence/src/throughput.rs#L33-L69","documentation":"samples() runs a candidate chunker `count` times over the fixture to collect timing samples. A count of zero would produce no durations and no throughput data, so the function rejects it up front rather than returning an empty or NaN timing result.","triggerScenarios":"Calling samples() (directly or via measure) with count: 0, e.g. a CLI/config option like --samples 0 or a computed sample count that evaluated to zero.","commonSituations":"Passing 0 samples via command-line flag or config file; computing sample count from an env var or default that resolves to 0; integer division truncating a configured duration into 0 samples.","solutions":["Pass a positive sample count (e.g. >= 3) when calling samples()/measure()","Clamp or validate the configured count before the call: if count == 0 { count = DEFAULT_SAMPLES; }","Reject zero/negative sample counts at config parsing time with a clear message"],"exampleFix":"// before\nlet timing = measure(&candidate, &fixture, true, cfg.samples)?;\n// after\nlet count = cfg.samples.max(1);\nlet timing = measure(&candidate, &fixture, true, count)?;","handlingStrategy":"validation","validationCode":"// rust\nlet count = configured_samples.unwrap_or(DEFAULT_SAMPLES);\nanyhow::ensure!(count > 0, \"throughput sample count must be positive, got {count}\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate sample-count config values when parsing CLI/config","Use nonzero unsigned types (NonZeroUsize) for sample counts","Provide a sensible default instead of defaulting to 0"],"tags":["invalid-argument","throughput","rust"],"backgroundTag":"invalid-argument-value","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}