affaan-m/ECC · error

at least one non-empty

Error message

at least one non-empty {kind} reference is required

What it means

normalize_refs validates that the trace_refs/evidence_refs passed to HarnessCandidate::new contain at least one entry and that no entry is blank or whitespace-only. The library requires every candidate to carry at least one non-empty reference for its content address. An empty vector or a list containing "" or " " triggers this error, with {kind} substituted by the parameter name (trace/evidence).

Solutions

  1. Supply at least one meaningful (non-blank) reference in the refs vector before calling new.
  2. Filter out blank entries before constructing: refs.into_iter().map(|s| s.trim().to_string()).filter(|s| !s.is_empty()).collect().
  3. Fix the source config/script so the refs key is populated (e.g. ensure the artifact path or commit sha is generated).
  4. Validate inputs at the call site with an early check that fails with a clearer message naming the missing ref kind.

Example fix

// before
let candidate = HarnessCandidate::new(vec![], evidence_refs)?;

// after
let trace_refs: Vec<String> = collected
    .into_iter()
    .map(|s| s.trim().to_string())
    .filter(|s| !s.is_empty())
    .collect();
if trace_refs.is_empty() {
    anyhow::bail!("no trace refs collected before building candidate");
}
let candidate = HarnessCandidate::new(trace_refs, evidence_refs)?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_refs(refs: &[String]) -> bool {
    !refs.is_empty() && refs.iter().all(|r| !r.trim().is_empty())
}

Type guard

fn non_empty_refs(refs: Vec<String>) -> Option<Vec<String>> {
    let cleaned: Vec<String> = refs.into_iter().map(|r| r.trim().to_string()).filter(|r| !r.is_empty()).collect();
    (!cleaned.is_empty()).then_some(cleaned)
}

Try / catch

match HarnessCandidate::new(trace_refs, evidence_refs) {
    Ok(c) => proceed(c),
    Err(e) if e.to_string().contains("non-empty") => bail!("trace/evidence refs missing from config"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: HarnessCandidate::new called with trace_refs: vec![] or evidence_refs: vec![]; passing a list containing an empty string or whitespace-only entry such as vec![String::new()] or vec![" ".into()]; programmatic construction from a config where a refs key was missing and defaulted to empty.

Common situations: Config file omits trace_refs/evidence_refs so an empty Vec is passed; a CI pipeline builds the refs list dynamically and a step produced no output; splitting a comma-separated string of refs yields an empty trailing element.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/e2d925c2e0cb6a81. Report an issue: GitHub.

Appendix: source

Thrown at ecc2/src/harness_eval.rs:261

        Ok(Self::new(
            serde_json::from_str(&self.canonical_config)?,
            self.trace_refs.clone(),
            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()

View on GitHub (pinned to 8321021c54)