ruvnet/ruflo · error · Error
message contentDigest does not match canonical content
Error message
message contentDigest does not match canonical content
What it means
The message's declared contentDigest does not match the digest recomputed from its content via harnessMessageContentDigest — the envelope claims different content than it carries. The message is quarantined under content-digest-mismatch and rejected, as digest mismatch indicates corruption or tampering.
Source
Thrown at v3/@claude-flow/codex/src/harness/in-memory-inbox-reference.ts:79
constructor(private readonly now: () => number = Date.now) {}
send(message: HarnessMessage): MessageReceipt {
if (!message.messageId.trim() || !message.issuer.trim() || !message.audience.trim()) {
throw new Error('message ID, issuer, and audience are required');
}
const identity = inMemoryInboxIdentityKey(message.issuer, message.messageId);
const receivedAt = new Date(this.now()).toISOString();
let suppliedDigest: string;
try {
suppliedDigest = harnessMessageContentDigest(message.content);
} catch {
this.quarantine(message, 'content-digest-mismatch', receivedAt);
throw new Error('message content is not canonical JSON');
}
if (suppliedDigest !== message.contentDigest) {
this.quarantine(message, 'content-digest-mismatch', receivedAt);
throw new Error('message contentDigest does not match canonical content');
}
try {
parseCanonicalUnsigned(message.sequence, 'message sequence');
} catch {
throw new Error('message sequence must be a canonical unsigned decimal integer');
}
if (message.expiresAt !== undefined && !Number.isFinite(Date.parse(message.expiresAt))) {
throw new Error('message expiresAt must be an ISO timestamp');
}
const envelopeDigest = sha256(canonicalJson(message));
const prior = this.byIdentity.get(identity);
if (prior) {
if (prior.issuer !== message.issuer || prior.messageId !== message.messageId) {
throw new Error('inbox identity hash collision');
}
if (prior.envelopeDigest !== envelopeDigest) {
this.quarantine(message, 'message-id-content-conflict', receivedAt);View on GitHub (pinned to fa13ee4ad6)
Solutions
- Compute contentDigest as sha256 over the canonical JSON form of the content, not over the raw object.
- Recompute the digest after any content mutation before sending the message.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at v3/@claude-flow/codex/src/harness/in-memory-inbox-reference.ts:79 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/b39529dff1841025.
Report an issue: GitHub.