JuliusBrussee/caveman · error
ccr: typed object content_hash does not match data
Error message
ccr: typed object content_hash does not match data
What it means
prepareObject verifies that a typed Object's ContentHash equals "sha256:" + hex(sha256(Data)) when provided. A mismatch means the declared hash does not describe the actual bytes, so the store refuses the object to protect integrity; pass ContentHash empty and the store computes it for you.
Solutions
- Leave obj.ContentHash empty and let prepareObject compute it from Data.
- If supplying a hash, recompute it over the exact bytes in obj.Data right before the call.
- Ensure the format is "sha256:" + lowercase hex digest of the data.
- Check for code paths that mutate Data after hashing and reorder them.
Example fix
// before obj.Data = transform(obj.Data) obj.ContentHash = oldHash // stale // after obj.Data = transform(obj.Data) sum := sha256.Sum256(obj.Data) obj.ContentHash = "sha256:" + hex.EncodeToString(sum[:])
Defensive patterns
Strategy: validation
Validate before calling
func hashData(data []byte) string {
s := sha256.Sum256(data)
return "sha256:" + hex.EncodeToString(s[:])
}
// call site: if obj.ContentHash != "" && obj.ContentHash != hashData(obj.Data) { reject } Try / catch
if strings.Contains(err.Error(), "content_hash does not match") {
obj.ContentHash = "" // let store compute
return store.PutObject(obj)
} Prevention
- Prefer leaving ContentHash empty and letting the store compute it.
- Freeze Data before hashing; never mutate after.
- Hash the exact bytes stored, not a pre-transform variant.
- Keep a helper for the "sha256:" + hex format to avoid drift.
When it happens
Trigger: PutObject with obj.ContentHash pre-set from different data than obj.Data: data mutated after hashing, hash computed over a compressed variant while Data holds raw bytes, or hash copied from a previous object version.
Common situations: Caching hashes computed before a later mutation of Data; hash copied from an upstream payload that was transformed (re-encoded, trimmed) before storage; wrong hash format (missing "sha256:" prefix or non-hex digest).
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
- ccr: typed object byte lengths cannot be negative
- ccr: typed object session_id is required
- signature check failed for
- signature check failed for
- adapter-specific build_sha256 values must differ
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/e926bea2c6cc7943.
Report an issue: GitHub.
Appendix: source
Thrown at engine/ccr/store.go:134
return Object{}, fmt.Errorf("ccr: unknown currentness %q", obj.Currentness)
}
if obj.Lifecycle == "" {
obj.Lifecycle = Hot
}
if obj.Lifecycle != Hot && obj.Lifecycle != Warm && obj.Lifecycle != Cold && obj.Lifecycle != LifecycleArchived {
return Object{}, fmt.Errorf("ccr: unknown lifecycle %q", obj.Lifecycle)
}
if obj.CreatedAt.IsZero() {
obj.CreatedAt = time.Now().UTC()
} else {
obj.CreatedAt = obj.CreatedAt.UTC()
}
dataSum := sha256.Sum256(obj.Data)
computedHash := "sha256:" + hex.EncodeToString(dataSum[:])
if obj.ContentHash == "" {
obj.ContentHash = computedHash
} else if obj.ContentHash != computedHash {
return Object{}, errors.New("ccr: typed object content_hash does not match data")
}
if obj.OriginalByteLength == 0 {
obj.OriginalByteLength = len(obj.Data)
}
if obj.StoredByteLength == 0 {
obj.StoredByteLength = len(obj.Data)
}
if obj.OriginalByteLength < 0 || obj.StoredByteLength < 0 {
return Object{}, errors.New("ccr: typed object byte lengths cannot be negative")
}
if obj.ID == "" {
identity := strings.Join([]string{string(obj.Type), obj.SessionID, obj.Source, obj.RepositoryState, obj.ContentHash}, "\x00")
sum := sha256.Sum256([]byte(identity))
obj.ID = "ccr_obj_" + hex.EncodeToString(sum[:16])
}
obj.Dependencies = append([]string(nil), obj.Dependencies...)
obj.Data = bytes.Clone(obj.Data)
return obj, nilView on GitHub (pinned to 3ee70a1026)