JuliusBrussee/caveman · error
cannot read pending agent-native removal journal
Error message
cannot read pending ${agent} agent-native removal journal: ${(error as Error).message} What it means
Same pattern for the pending bundle *removal* journal — the staged record of a bundle uninstall not yet applied. Non-ENOENT failures (permission, invalid JSON, schema mismatch) are wrapped in this error; a missing file yields null.
Solutions
- Delete the corrupt pending removal journal to clear the stuck state.
- Repair file permissions on the journal path.
- Check the JSON conforms to schema_version 1 with the expected fields.
- Re-run the uninstall command after cleanup.
Defensive patterns
Strategy: try-catch
Validate before calling
try { JSON.parse(readFileSync(removalJournalPath(agent), 'utf8')); } catch { console.warn('removal journal corrupt — safe to delete'); } Type guard
function isRemovalJournal(v: unknown): v is AgentNativeBundleJournal {
return typeof v === 'object' && v !== null && (v as any).schema_version === 1 &&
['claude','codex'].includes((v as any).agent);
} Try / catch
try { uninstall() } catch (e) { if (String(e.message).includes('cannot read pending') && String(e.message).includes('removal')) { fs.rmSync(removalJournalPath, { force: true }); uninstall(); } } Prevention
- Complete or cleanly abort uninstalls instead of force-killing the process.
- Validate JSON before manually restoring config from backups.
- Pin one CLI version per machine to avoid schema drift.
When it happens
Trigger: readPendingAgentNativeBundleRemoval(agent) fails on the removal journal path with EACCES/EISDIR, malformed JSON, or schema validation failure (schema_version !== 1, wrong agent, missing cloud_mcp/skills).
Common situations: Interrupted uninstall left a partial removal journal; manual edits broke the JSON; version mismatch on schema.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- cannot read agent-native bundle journal
- cannot read pending agent-native bundle journal
- cannot read pending transaction
- caveman agent: invalid .caveman/provider.json
- : MCP ownership journal failed; native config may already…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/7bcb3af77c8b9899.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:2607
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}`);
}
}
type McpServerMarker = { command: string; args: string[]; config_path?: string; schema_version?: 1 };
function mcpServerToolName(serverName: string): string | undefined {
if (serverName === "caveman") return "caveman_retrieve";
if (serverName === "caveman-browse") return "caveman_browse";
if (serverName === "caveman-cloud") return "caveman_context";
if (serverName === "caveman-delegate") return "caveman_delegate";
return undefined;
}
function parseMcpServerMarkerBytes(agent: string, serverName: string, bytes: Buffer): McpServerMarker | null {
try {
const value = JSON.parse(bytes.toString("utf8")) as Record<string, unknown>;
const expectedTool = mcpServerToolName(serverName);
if (!expectedTool || value.tool !== expectedTool) return null;View on GitHub (pinned to 3ee70a1026)