{"record":{"id":"b39529dff1841025","repo":"ruvnet/ruflo","slug":"message-contentdigest-does-not-match-canonical-con","errorCode":null,"errorMessage":"message contentDigest does not match canonical content","messagePattern":"message contentDigest does not match canonical content","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/in-memory-inbox-reference.ts","lineNumber":79,"sourceCode":"\n  constructor(private readonly now: () => number = Date.now) {}\n\n  send(message: HarnessMessage): MessageReceipt {\n    if (!message.messageId.trim() || !message.issuer.trim() || !message.audience.trim()) {\n      throw new Error('message ID, issuer, and audience are required');\n    }\n    const identity = inMemoryInboxIdentityKey(message.issuer, message.messageId);\n    const receivedAt = new Date(this.now()).toISOString();\n    let suppliedDigest: string;\n    try {\n      suppliedDigest = harnessMessageContentDigest(message.content);\n    } catch {\n      this.quarantine(message, 'content-digest-mismatch', receivedAt);\n      throw new Error('message content is not canonical JSON');\n    }\n    if (suppliedDigest !== message.contentDigest) {\n      this.quarantine(message, 'content-digest-mismatch', receivedAt);\n      throw new Error('message contentDigest does not match canonical content');\n    }\n    try {\n      parseCanonicalUnsigned(message.sequence, 'message sequence');\n    } catch {\n      throw new Error('message sequence must be a canonical unsigned decimal integer');\n    }\n    if (message.expiresAt !== undefined && !Number.isFinite(Date.parse(message.expiresAt))) {\n      throw new Error('message expiresAt must be an ISO timestamp');\n    }\n\n    const envelopeDigest = sha256(canonicalJson(message));\n    const prior = this.byIdentity.get(identity);\n    if (prior) {\n      if (prior.issuer !== message.issuer || prior.messageId !== message.messageId) {\n        throw new Error('inbox identity hash collision');\n      }\n      if (prior.envelopeDigest !== envelopeDigest) {\n        this.quarantine(message, 'message-id-content-conflict', receivedAt);","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/in-memory-inbox-reference.ts#L61-L97","documentation":"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.","triggerScenarios":"Thrown at v3/@claude-flow/codex/src/harness/in-memory-inbox-reference.ts:79 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}