JuliusBrussee/caveman · error · Error
Gemini integration journal lacks owned routing block
Error message
Gemini integration journal lacks owned routing block
What it means
The gemini-env operation removes routing by exact string: it deletes the owned.route_block that was recorded in the journal when ~/.gemini/.env was written. A journal whose gemini-env operation lacks a string route_block (older schema, foreign writer, hand edit) cannot drive restoration, so restoreNativeOperation() refuses immediately - even before looking at the env file.
Source
Thrown at packages/cli/src/index.ts:7645
: {};
const beforeServers = beforeRoot.mcpServers && typeof beforeRoot.mcpServers === "object" && !Array.isArray(beforeRoot.mcpServers)
? beforeRoot.mcpServers as Record<string, unknown>
: {};
const installed = operation.owned?.installed_mcp;
if (servers.caveman !== undefined && JSON.stringify(servers.caveman) !== JSON.stringify(installed)) {
throw new Error("Gemini caveman MCP entry changed after enable; refusing destructive disable");
}
if (servers.caveman !== undefined) {
if (beforeServers.caveman === undefined) delete servers.caveman;
else servers.caveman = beforeServers.caveman;
}
if (Object.keys(servers).length > 0) currentRoot.mcpServers = servers;
else delete currentRoot.mcpServers;
return jsonBytes(currentRoot);
}
if (operation.kind === "gemini-env") {
const block = operation.owned?.route_block;
if (typeof block !== "string") throw new Error("Gemini integration journal lacks owned routing block");
const text = current.toString("utf8");
if (text.includes(GEMINI_NATIVE_ENV_BEGIN) && !text.includes(block)) {
throw new Error("Gemini routing block changed after enable; refusing destructive disable");
}
return Buffer.from(text.replace(`${block}\n\n`, "").replace(`\n\n${block}\n`, "\n").replace(`${block}\n`, "").replace(block, ""));
}
if (operation.kind === "opencode-plugin" || operation.kind === "pi-extension") {
throw new Error(`${operation.file} changed after enable; refusing destructive disable`);
}
if (operation.kind === "opencode-config") {
const root = parseJsonFileObject(operation.file, current);
const providers = root.provider && typeof root.provider === "object" && !Array.isArray(root.provider) ? root.provider as Record<string, unknown> : {};
const routes = operation.owned?.routes && typeof operation.owned.routes === "object" && !Array.isArray(operation.owned.routes) ? operation.owned.routes as Record<string, unknown> : {};
const previousRoutes = operation.owned?.previous_routes && typeof operation.owned.previous_routes === "object" && !Array.isArray(operation.owned.previous_routes) ? operation.owned.previous_routes as Record<string, unknown> : {};
for (const providerID of ["openai", "anthropic"]) {
const provider = providers[providerID] && typeof providers[providerID] === "object" && !Array.isArray(providers[providerID]) ? providers[providerID] as Record<string, unknown> : {};
const options = provider.options && typeof provider.options === "object" && !Array.isArray(provider.options) ? provider.options as Record<string, unknown> : {};
if (options.baseURL !== undefined && options.baseURL !== routes[providerID]) {View on GitHub (pinned to 2f49f0e1a3)
Solutions
- Upgrade caveman on this machine and run `caveman doctor gemini --fix` so the journal is repaired or rewritten by the current version.
- If unrecoverable, remove the '# >>> caveman:native-routing' block from ~/.gemini/.env by hand, delete ~/.caveman/integrations/gemini.json (and .pending-gemini.json if present), then `caveman enable gemini` fresh.
- Never hand-edit files under ~/.caveman/integrations.
Defensive patterns
Strategy: type-guard
Type guard
import { readFileSync } from 'node:fs';
function geminiEnvHasRouteBlock(home = process.env.HOME!): boolean {
try {
const journal = JSON.parse(readFileSync(`${home}/.caveman/integrations/gemini.json`, 'utf8'));
const op = (journal?.operations as any[] | undefined)?.find((o) => o?.kind === 'gemini-env');
return typeof op?.owned?.route_block === 'string';
} catch { return false; }
}
if (!geminiEnvHasRouteBlock()) { console.error('gemini journal lacks owned.route_block; upgrade caveman and run doctor gemini --fix'); process.exit(1); } Try / catch
try {
await runCaveman('disable', 'gemini');
} catch (e) {
if (/journal lacks owned routing block/.test(String(e))) {
// journal predates the current schema: upgrade caveman, run 'caveman doctor gemini --fix', then retry
throw e;
}
throw e;
} Prevention
- Upgrade caveman before disabling integrations created by much older versions
- Never hand-edit integration journals
- Keep ~/.caveman and the caveman binary versioned together in provisioning
When it happens
Trigger: `caveman disable gemini` when ~/.caveman/integrations/gemini.json contains a gemini-env operation whose owned.route_block is missing or not a string - a journal from an older caveman version or one edited by hand.
Common situations: Upgrading caveman across journal-schema changes; users 'fixing' journals after reading docs; restoring ~/.caveman from a mixed-version backup.
Related errors
- Aider integration journal lacks owned blocks
- Hermes integration journal lacks owned routing block
- Codex integration journal lacks owned blocks
- Gemini caveman MCP entry changed after enable; refusing dest
- Gemini routing block changed after enable; refusing destruct
AI-assisted analysis of JuliusBrussee/caveman@2f49f0e1a3 (2026-08-18).
Data as JSON: /api/errors/19998dd9472140a2.
Report an issue: GitHub.