JuliusBrussee/caveman · error · Error

cannot read pending ${agent} agent-native bundle journal: ${

Error message

cannot read pending ${agent} agent-native bundle journal: ${(error as Error).message}

What it means

readPendingAgentNativeBundleJournal() reads the '.pending' variant of the agent-native bundle journal — the transaction record of an in-flight skill/MCP installation. A non-ENOENT error (bad JSON, or shape validation failing: schema_version !== 1, wrong agent, missing cloud_mcp, non-array skills) is rethrown with this message before any recovery is attempted.

Source

Thrown at packages/cli/src/index.ts:2309

      throw new Error("unsupported bundle journal");
    }
    return value;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
    throw new Error(`cannot read ${agent} agent-native bundle journal: ${(error as Error).message}`);
  }
}

function readPendingAgentNativeBundleJournal(agent: "claude" | "codex"): AgentNativeBundleJournal | null {
  try {
    const value = JSON.parse(readFileSync(agentNativeBundleJournalPath(agent, true), "utf8")) as AgentNativeBundleJournal;
    if (value.schema_version !== 1 || value.agent !== agent || !value.cloud_mcp || !Array.isArray(value.skills)) {
      throw new Error("unsupported pending bundle journal");
    }
    return value;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
    throw new Error(`cannot read pending ${agent} agent-native bundle journal: ${(error as Error).message}`);
  }
}

function readPendingAgentNativeBundleRemoval(agent: "claude" | "codex"): AgentNativeBundleJournal | null {
  try {
    const value = JSON.parse(readFileSync(agentNativeBundleRemovalJournalPath(agent), "utf8")) as AgentNativeBundleJournal;
    if (value.schema_version !== 1 || value.agent !== agent || !value.cloud_mcp || !Array.isArray(value.skills)) {
      throw new Error("unsupported pending bundle removal journal");
    }
    return value;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
    throw new Error(`cannot read pending ${agent} agent-native removal journal: ${(error as Error).message}`);
  }
}

function readMcpServerMarker(agent: string, serverName: string): { command: string; args: string[] } | null {
  try {

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Inspect the pending journal file and compare it to the committed journal for the agent
  2. If the interrupted setup's target state is irrelevant, delete the pending journal and re-run setup to redo the bundle cleanly
  3. Ensure only one caveman process runs setup per agent (the integration lock) to avoid partial writes
Defensive patterns

Strategy: try-catch

Validate before calling

function pendingJournalIntact(p: string): boolean {
  try {
    const v = JSON.parse(readFileSync(p, "utf8"));
    return v.schema_version === 1 && Array.isArray(v.skills) && !!v.cloud_mcp;
  } catch { return false; }
}

Type guard

function isPendingJournalReadError(e: unknown): boolean {
  return e instanceof Error && e.message.includes("cannot read pending ") && e.message.includes("bundle journal");
}

Try / catch

try {
  runCavemanAgentCommand("codex");
} catch (e) {
  if (isPendingJournalReadError(e)) {
    // an interrupted setup left a partial .pending journal — resolve it before any agent command
  } else throw e;
}

Prevention

When it happens

Trigger: A previous `caveman setup` / agent-native install was killed mid-transaction leaving a partially written .pending journal, then any later agent command runs recovery and hits the malformed file; or a CLI version skew changed the journal schema between write and read.

Common situations: Ctrl-C or SIGKILL during `caveman claude` setup; power loss; two caveman processes racing (no integration lock held); manual editing of the pending journal.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/059eacf7ca8b4334. Report an issue: GitHub.