affaan-m/ECC · error

references exceed bounded limits

Error message

{kind} references exceed bounded limits

What it means

normalize_refs enforces bounded limits on trace_refs/evidence_refs: at most 100 references total, and each reference at most 4096 bytes. This protects the content-addressed candidate id from unbounded growth. Exceeding either bound throws this error with {kind} naming the offending parameter.

Solutions

  1. Deduplicate and trim the refs list, then cap it at 100 entries before calling new.
  2. Shorten each reference to a stable short form (commit sha, artifact id, or relative path) instead of a full URL/blob.
  3. Batch large evidence sets into multiple candidates, each with its own bounded refs list.
  4. Add a pre-call assertion so oversized input fails at the producer with a clear message.

Example fix

// before
let candidate = HarnessCandidate::new(all_traces /* 3,000 entries */, evidence_refs)?;

// after
let mut trace_refs: Vec<&String> = all_traces.iter().collect();
trace_refs.sort();
trace_refs.dedup();
let trace_refs: Vec<String> = trace_refs.into_iter().take(100).cloned().collect();
let candidate = HarnessCandidate::new(trace_refs, evidence_refs)?;
Defensive patterns

Strategy: validation

Validate before calling

fn refs_within_bounds(refs: &[String]) -> bool {
    refs.len() <= 100 && refs.iter().all(|r| r.len() <= 4096)
}

Type guard

fn bounded_refs(refs: Vec<String>, max: usize) -> Result<Vec<String>, String> {
    if refs.len() > max || refs.iter().any(|r| r.len() > 4096) {
        return Err("refs exceed bounded limits".into());
    }
    Ok(refs)
}

Try / catch

match HarnessCandidate::new(trace_refs, evidence_refs) {
    Ok(c) => proceed(c),
    Err(e) if e.to_string().contains("bounded limits") => proceed(batch_into_multiple_candidates(trace_refs, evidence_refs)?),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: HarnessCandidate::new called with more than 100 entries in trace_refs or evidence_refs; any single reference string longer than 4096 bytes (e.g. an embedded blob or a very long path/URL).

Common situations: Accidentally passing all historical traces instead of the current batch; a ref string that accidentally embeds a whole JSON payload or a data: URI; concatenating ref lists from multiple runs without deduplication.

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/6c1906b2cc720313. Report an issue: GitHub.

Appendix: source

Thrown at ecc2/src/harness_eval.rs:264

            self.evidence_refs.clone(),
        )?
        .id)
    }
}

#[derive(Serialize)]
struct CanonicalCandidateArtifact<'a> {
    config: Value,
    trace_refs: &'a [String],
    evidence_refs: &'a [String],
}

fn normalize_refs(kind: &str, refs: Vec<String>) -> Result<Vec<String>> {
    if refs.is_empty() || refs.iter().any(|reference| reference.trim().is_empty()) {
        bail!("at least one non-empty {kind} reference is required");
    }
    if refs.len() > 100 || refs.iter().any(|reference| reference.len() > 4096) {
        bail!("{kind} references exceed bounded limits");
    }
    let mut normalized = refs
        .into_iter()
        .map(|reference| reference.trim().to_string())
        .collect::<Vec<_>>();
    normalized.sort();
    normalized.dedup();
    Ok(normalized)
}

fn sha256_hex(bytes: &[u8]) -> String {
    Sha256::digest(bytes)
        .iter()
        .map(|byte| format!("{byte:02x}"))
        .collect()
}

fn canonicalize(value: Value) -> Value {

View on GitHub (pinned to 8321021c54)