JuliusBrussee/caveman · error · Error
cannot read pending ${label} transaction: ${(error as Error)
Error message
cannot read pending ${label} transaction: ${(error as Error).message} What it means
Wraps any non-ENOENT error from reading or parsing the pending transaction journal file (readFileSync/JSON.parse) during recovery. It means the journal exists but could not be read as JSON — for example a permissions or I/O error — and recovery is aborted so it cannot act on incomplete transaction state.
Source
Thrown at packages/cli/src/index.ts:12359
};
function ownedMcpPendingLabel(agent?: string, serverName?: string): string {
return agent && serverName ? `${agent} ${serverName} MCP` : "owned MCP";
}
function readOwnedMcpPendingJournalAt(
path: string,
expected: { agent?: "kilo" | "qwen"; serverName?: string; configPath?: string; locatorPath?: string } = {},
): ReadOwnedMcpPendingJournal | null {
const label = ownedMcpPendingLabel(expected.agent, expected.serverName);
let bytes: Buffer;
let value: Record<string, unknown>;
try {
bytes = readFileSync(path);
value = JSON.parse(bytes.toString("utf8")) as Record<string, unknown>;
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
throw new Error(`cannot read pending ${label} transaction: ${(error as Error).message}`);
}
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error(`pending ${label} transaction is malformed; refusing recovery`);
}
if (process.platform !== "win32" && (statSync(path).mode & 0o077) !== 0) {
throw new Error(`pending ${label} transaction has unsafe permissions; refusing recovery`);
}
const keys = [
"action", "agent", "config_after_sha256", "config_before_base64", "config_before_mode", "config_path",
"config_before_sha256", "marker_after_base64", "marker_after_sha256", "marker_before_base64", "marker_before_mode",
"marker_before_sha256", "marker_path", "schema_version", "server_name", "transaction_id",
].sort();
const journalAgent = value.agent;
const journalServer = value.server_name;
if (Object.keys(value).sort().join("\0") !== keys.join("\0")
|| value.schema_version !== 1
|| typeof value.transaction_id !== "string"
|| !/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(value.transaction_id)View on GitHub (pinned to 5184b3d11a)
Solutions
- Inspect the wrapped ${(error as Error).message} in the thrown error to identify the underlying errno or JSON parse failure.
- Fix file permissions/ownership on the .pending journal file (chmod 600, chown to the running user).
- If the file is corrupted, remove it (and the paired config/locator pending journals) and re-run the MCP server install to recreate clean state.
- Run the recovery under the same user account that created the transaction.
Example fix
// before sudo kilo mcp recover // after chown $USER ~/.kilo/mcp/*.pending && chmod 600 ~/.kilo/mcp/*.pending && kilo mcp recover
Defensive patterns
Strategy: try-catch
Validate before calling
try { fs.accessSync(journalPath, fs.constants.R_OK); } catch { /* cannot read: fix perms before recovery */ } Try / catch
try { recoverPending(); } catch (e) {
if (e.message.startsWith('cannot read pending')) {
// inspect cause after the colon; fix perms or delete corrupt journal
}
} Prevention
- Create journals with mode 0600 under the same user that runs recovery.
- Protect journals from concurrent writers (single CLI instance).
- Treat unexpected non-ENOENT read errors as corruption signals and recreate state.
When it happens
Trigger: readFileSync on the journal path fails with EACCES, EISDIR, or another errno other than ENOENT; JSON.parse fails because the file content is invalid JSON (both produce this wrapped error; ENOENT alone returns null).
Common situations: Journal file truncated or corrupted by a crash mid-write; file owned by root while recovery runs as the user; path is actually a directory; disk I/O errors.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- pending ${label} transaction has unsafe permissions; refusin
- pending ${label} transaction is malformed: ${(error as Error
AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-09-06).
Data as JSON: /api/errors/374e9daac13d63c3.
Report an issue: GitHub.