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

  1. Delete the corrupt pending removal journal to clear the stuck state.
  2. Repair file permissions on the journal path.
  3. Check the JSON conforms to schema_version 1 with the expected fields.
  4. 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

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


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)