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

  1. Verify hashes: recompute sha256 of the decoded base64 fields and confirm they equal the *_sha256 fields.
  2. Confirm the journal belongs to this agent/serverName and config_path; discard journals from other servers.
  3. Ensure action and marker_after are consistent: install ⇒ marker_after present; uninstall ⇒ null.
  4. 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

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.