JuliusBrussee/caveman · error · Error
journal bytes do not match declared transaction state
Error message
journal bytes do not match declared transaction state
What it means
Thrown after field-level validation when the decoded journal bytes are internally inconsistent with the declared transaction: marker bytes don't parse as valid MCP server markers for the agent/server, a marker's embedded config_path disagrees with journal config_path, config/marker hashes don't match the decoded bytes, or the action ('install') doesn't agree with markerAfter being present/absent. It is a final integrity check that prevents applying a self-contradictory journal.
Source
Thrown at packages/cli/src/index.ts:12411
|| !validOptionalHash(value.config_after_sha256)
|| !validOptionalHash(value.marker_before_sha256)
|| !validOptionalHash(value.marker_after_sha256)) {
throw new Error(`pending ${label} transaction is malformed; refusing recovery`);
}
try {
const configBefore = decodePendingBytes(value.config_before_base64, "config_before_base64");
const markerBefore = decodePendingBytes(value.marker_before_base64, "marker_before_base64");
const markerAfter = decodePendingBytes(value.marker_after_base64, "marker_after_base64");
if (optionalBytesHash(configBefore) !== value.config_before_sha256
|| optionalBytesHash(markerBefore) !== value.marker_before_sha256
|| optionalBytesHash(markerAfter) !== value.marker_after_sha256
|| (markerBefore !== null && !validMcpMarkerBytes(markerBefore, journalAgent, journalServer))
|| (markerAfter !== null && !validMcpMarkerBytes(markerAfter, journalAgent, journalServer))
|| (markerBefore !== null && parseMcpServerMarkerBytes(journalAgent, journalServer, markerBefore)?.config_path !== undefined
&& parseMcpServerMarkerBytes(journalAgent, journalServer, markerBefore)?.config_path !== value.config_path)
|| (markerAfter !== null && parseMcpServerMarkerBytes(journalAgent, journalServer, markerAfter)?.config_path !== value.config_path)
|| (value.action === "install") !== (markerAfter !== null)) {
throw new Error("journal bytes do not match declared transaction state");
}
return {
journal: value as OwnedMcpPendingJournal,
configBefore,
markerBefore,
markerAfter,
path,
bytes,
};
} catch (error) {
throw new Error(`pending ${label} transaction is malformed: ${(error as Error).message}`);
}
}
function readOwnedMcpPendingLocator(agent: "kilo" | "qwen", serverName: string): ReadOwnedMcpPendingJournal | null {
const path = canonicalMcpConfigPath(mcpPendingJournalPath(agent, serverName));
return readOwnedMcpPendingJournalAt(path, { agent, serverName, locatorPath: path });
}View on GitHub (pinned to 5184b3d11a)
Solutions
- Verify hashes: recompute sha256 of the decoded base64 fields and confirm they equal the *_sha256 fields.
- Confirm the journal belongs to this agent/serverName and config_path; discard journals from other servers.
- Ensure action and marker_after are consistent: install ⇒ marker_after present; uninstall ⇒ null.
- Delete the inconsistent .pending journals and redo the transaction cleanly.
Example fix
// before
{ "action": "install", "marker_after_base64": null, ... }
// after
{ "action": "install", "marker_after_base64": "<valid marker bytes>", ... } Defensive patterns
Strategy: validation
Validate before calling
// verify cross-field consistency before recovery
const h = b => 'sha256:' + require('crypto').createHash('sha256').update(b).digest('hex');
if (configBefore && h(configBefore) !== j.config_before_sha256) throw new Error('hash mismatch');
if ((j.action === 'install') !== (j.marker_after_base64 !== null)) throw new Error('action/marker mismatch'); Try / catch
try { recoverPending(); } catch (e) {
if (e.message === 'journal bytes do not match declared transaction state') { /* discard journal; redo transaction */ }
} Prevention
- Recompute and compare hashes of decoded bytes whenever you touch a journal.
- Keep marker bytes, agent/serverName, and config_path mutually consistent at write time.
- Never partially update one field of a journal; write it atomically.
When it happens
Trigger: A journal whose config_before_base64 bytes hash to something other than config_before_sha256; marker files saved under the wrong agent/serverName; action=install but marker_after_base64 is null; a marker whose internal config_path differs from journal config_path.
Common situations: Partially edited journals; journals copied between different MCP server configurations; a writer bug mixing marker bytes from another server; corruption that passes JSON validation but breaks cross-field consistency.
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.
AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-09-06).
Data as JSON: /api/errors/49cdc95d184d0c36.
Report an issue: GitHub.