affaan-m/ECC · error
scores must be finite and between 0 and 1
Error message
scores must be finite and between 0 and 1
What it means
`compare` validates each sample's `candidate_score` and `baseline_score`: both must be finite (not NaN or infinity) and within the inclusive range 0.0..=1.0. Non-finite or out-of-range values would corrupt mean, delta, and win-rate calculations. Any single bad sample causes the whole comparison to be rejected.
Solutions
- Normalize scores to [0,1] before constructing PairedSample (clamp and map the metric).
- Sanitize or drop non-finite scores (NaN/inf) before collecting samples.
- Check the upstream scoring function for NaN sources (empty outputs, division by zero).
Example fix
// before
let score = raw_value;
// after
let score = if raw_value.is_finite() { raw_value.clamp(0.0, 1.0) } else { 0.0 }; Defensive patterns
Strategy: validation
Validate before calling
anyhow::ensure!(
samples.iter().all(|s| s.candidate_score.is_finite()
&& s.baseline_score.is_finite()
&& (0.0..=1.0).contains(&s.candidate_score)
&& (0.0..=1.0).contains(&s.baseline_score)),
"sample scores must be finite and in [0,1]"
); Try / catch
match evaluator.compare(&samples) {
Ok(c) => c,
Err(e) if e.to_string().contains("finite and between 0 and 1") => {
eprintln!("Score out of range; check scoring/normalization step");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Clamp and normalize metrics into [0,1] at the scoring boundary
- Replace non-finite scores (NaN/inf) with a sentinel before sampling
- Add a sanity check on scores right after each task evaluation
When it happens
Trigger: Calling `compare` with a sample whose score is NaN, infinite, negative, or greater than 1.0 — typically from an unnormalized metric or a failed/errored evaluation recorded as NaN.
Common situations: Metrics that are not normalized to [0,1] passed in directly, division-by-zero in score computation producing NaN, deserialized JSON containing null/defaulted scores, or a task that timed out and produced an infinite penalty score.
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
- genre has invalid total duration
- reference probe numeric evidence must be finite real values
- sample seeds must be unique
- samples cannot be empty
- -32602
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/6a06a448f45097b2.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/harness_eval.rs:539
if samples.is_empty() {
bail!("samples cannot be empty");
}
if samples
.iter()
.map(|sample| sample.seed)
.collect::<BTreeSet<_>>()
.len()
!= samples.len()
{
bail!("sample seeds must be unique");
}
if samples.iter().any(|s| {
!s.candidate_score.is_finite()
|| !s.baseline_score.is_finite()
|| !(0.0..=1.0).contains(&s.candidate_score)
|| !(0.0..=1.0).contains(&s.baseline_score)
}) {
bail!("scores must be finite and between 0 and 1");
}
let count = samples.len();
let candidate_mean = samples.iter().map(|s| s.candidate_score).sum::<f64>() / count as f64;
let baseline_mean = samples.iter().map(|s| s.baseline_score).sum::<f64>() / count as f64;
let mean_delta = candidate_mean - baseline_mean;
let win_rate = samples
.iter()
.filter(|s| s.candidate_score > s.baseline_score)
.count() as f64
/ count as f64;
let mut failures = Vec::new();
if count < self.min_samples {
failures.push(format!(
"minimum sample count is {}, got {count}",
self.min_samples
));
}
if mean_delta < self.min_mean_delta {View on GitHub (pinned to 8321021c54)