affaan-m/ECC · error
score must be finite and between 0 and 1
Error message
score must be finite and between 0 and 1
What it means
During evaluate, the recorded evaluator looks up the pre-recorded score for a (candidate_id, seed) pair and validates it. This error is thrown when the recorded score value is NaN, infinite, or outside the 0.0..=1.0 inclusive range. Scores must be normalized probabilities in [0, 1].
Solutions
- Clamp or normalize recorded scores to the range [0.0, 1.0] before inserting them into the recorder.
- Check the recording metric: if it is a percentage, divide by 100; if raw, rescale to [0,1].
- Guard against NaN at record time (skip or fix samples producing NaN, e.g. division by zero).
- Validate every recorded score (score.is_finite() && (0.0..=1.0).contains(&score)) before running evaluation.
Example fix
// before recorder.record(candidate_id, seed, accuracy * 100.0)?; // 87.5 -> bails at evaluate // after let score = (accuracy * 100.0 / 100.0).clamp(0.0, 1.0); assert!(score.is_finite()); recorder.record(candidate_id, seed, score)?;
Defensive patterns
Strategy: validation
Validate before calling
fn valid_score(s: f64) -> bool { s.is_finite() && (0.0..=1.0).contains(&s) }
// check every score before evaluate:
debug_assert!(recorder_scores().values().copied().all(valid_score)); Type guard
fn is_normalized_score(s: f64) -> bool { s.is_finite() && (0.0..=1.0).contains(&s) } Try / catch
// map_err with normalization retry
match eval.evaluate(candidate_id, seed) {
Err(e) if e.to_string().contains("score must be finite") => {
// fix recording pipeline, clamp scores, rebuild evidence, retry once
}
other => other?,
} Prevention
- Normalize metrics to [0,1] at record time (clamp + rescale).
- Guard recording math against division by zero and NaN accumulation.
- Add a record-time assertion that every inserted score is finite and in range.
When it happens
Trigger: Calling evaluate (or evaluate_paired) with a seed/candidate pair whose pre-recorded score is NaN, f64::INFINITY, negative, or greater than 1.0 in the scores map built via the recorder.
Common situations: Recording raw unnormalized metrics (e.g. accuracy * 100, raw loss values, negative rewards); dividing by zero or accumulating float drift during recording producing NaN; recording scores from a metric whose valid range exceeds [0,1].
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
- -32602
- a claim token is required
- a confirmed nonempty coordinate is required
- a generated candidate cannot claim original-source identity
- A managed install plan with operations is required.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/75f571fc880e8513.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/harness_eval.rs:436
#[cfg(test)]
pub fn calls(&self) -> &[(String, u64)] {
&self.calls
}
}
impl Evaluator for RecordedEvaluator {
fn name(&self) -> &str {
&self.name
}
fn evaluate(&mut self, candidate_id: &str, seed: u64) -> Result<f64> {
self.calls.push((candidate_id.to_string(), seed));
let score = *self
.scores
.get(&(candidate_id.to_string(), seed))
.with_context(|| format!("missing recorded score for {candidate_id} seed {seed}"))?;
if !score.is_finite() || !(0.0..=1.0).contains(&score) {
bail!("score must be finite and between 0 and 1");
}
Ok(score)
}
fn health_check(&mut self, candidate_id: &str) -> Result<bool> {
if self
.health_candidate
.as_deref()
.is_some_and(|expected| expected != candidate_id)
{
bail!("health evidence does not match promoted candidate");
}
Ok(self.health_ok)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PairedSample {View on GitHub (pinned to 8321021c54)