affaan-m/ECC · error

candidate content address or canonical configuration is…

Error message

candidate content address or canonical configuration is invalid

What it means

`CandidateSpec::verify_integrity` recomputes the content address for the current canonical configuration and compares it with the stored/persisted `id`. If the stored id does not match the recomputed id (`self.id != self.id_for_v2()`), the candidate's identity and its content disagree — the record was corrupted, produced by a different algorithm version, or mutated after persistence. The error is a checksum-mismatch-style integrity failure surfacing at read/verification time.

Solutions

  1. Regenerate the candidate: rebuild the CandidateSpec from the current config via `CandidateSpec::new` and re-persist it so id and content are recomputed together.
  2. If the record is a legacy one, re-migrate it: compute `id_for_v2()` from its canonical_config and update the stored id (or use `legacy_id()` for old-scheme records).
  3. Diff the persisted canonical_config against what was originally submitted to find what mutated after the id was written.
  4. Do not hand-edit persisted candidate files; treat them as immutable content-addressed artifacts and delete+recreate instead.

Example fix

// before: stale id after config was edited on disk
let spec: CandidateSpec = load_candidate("candidates/abc.json")?;
spec.verify_integrity()?; // fails: id != id_for_v2()

// after: rebuild so identity matches content
let config = serde_json::from_str(&spec_raw.config)?;
let spec = CandidateSpec::new(config, spec_raw.trace_refs, spec_raw.evidence_refs)?;
spec.verify_integrity()?; // passes
Defensive patterns

Strategy: try-catch

Validate before calling

fn integrity_ok(spec: &CandidateSpec) -> bool {
    spec.id == spec.id_for_v2().unwrap_or_default()
}

Type guard

fn is_valid_candidate(spec: &CandidateSpec) -> bool {
    spec.verify_integrity().is_ok()
}

Try / catch

match spec.verify_integrity() {
    Ok(()) => use_spec(spec),
    Err(e) if e.to_string().contains("content address") => {
        // corrupted or legacy record: rebuild from source config
        let rebuilt = rebuild_and_persist(&spec.canonical_config)?;
        use_spec(&rebuilt)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `verify_integrity()` (directly or via `record_harness_candidate`) on a persisted CandidateSpec whose `id` field does not equal `id_for_v2()` computed from its current `canonical_config`, `trace_refs`, and `evidence_refs`.

Common situations: Manually editing a persisted candidate JSON file after it was written; old records persisted with a legacy hashing scheme (`legacy_id` = sha256 of canonical config alone) being verified under the v2 scheme; a migration or partial write that changed canonical_config without recomputing the id; copying a candidate record between environments where content differed.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — 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/6f2f2ad958b15d50. Report an issue: GitHub.

Appendix: source

Thrown at ecc2/src/harness_eval.rs:217

        }
        let artifact = serde_json::to_string(&CanonicalCandidateArtifact {
            config: serde_json::from_str(&canonical_config)?,
            trace_refs: &trace_refs,
            evidence_refs: &evidence_refs,
        })?;
        let id = sha256_hex(artifact.as_bytes());
        Ok(Self {
            id,
            canonical_config,
            trace_refs,
            evidence_refs,
        })
    }

    pub fn verify_integrity(&self) -> Result<()> {
        self.verify_persisted_id(&self.id)?;
        if self.id != self.id_for_v2()? {
            bail!("candidate content address or canonical configuration is invalid");
        }
        Ok(())
    }

    pub fn legacy_id(&self) -> String {
        sha256_hex(self.canonical_config.as_bytes())
    }

    pub fn verify_persisted_id(&self, persisted_id: &str) -> Result<()> {
        let value: Value = serde_json::from_str(&self.canonical_config)?;
        let rebuilt = Self::new(value, self.trace_refs.clone(), self.evidence_refs.clone())?;
        let is_v1 = persisted_id == self.legacy_id();
        let is_v2 = persisted_id == rebuilt.id;
        if rebuilt.canonical_config != self.canonical_config
            || (!is_v1 && !is_v2)
            || (is_v2
                && (rebuilt.trace_refs != self.trace_refs
                    || rebuilt.evidence_refs != self.evidence_refs))

View on GitHub (pinned to 8321021c54)