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

  1. Clamp or normalize recorded scores to the range [0.0, 1.0] before inserting them into the recorder.
  2. Check the recording metric: if it is a percentage, divide by 100; if raw, rescale to [0,1].
  3. Guard against NaN at record time (skip or fix samples producing NaN, e.g. division by zero).
  4. 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

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


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)